/// </summary>
public int Capacity => _array?.Length ?? 0;
+ /// <summary>Gets the current underlying array.</summary>
+ public T[] Buffer => _array;
+
/// <summary>
/// Gets the number of items in the array currently in use.
/// </summary>
Debug.Assert(index >= 0 && index < _count);
return _array[index];
}
- set
- {
- Debug.Assert(index >= 0 && index < _count);
- _array[index] = value;
- }
}
/// <summary>
--- /dev/null
+// 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.Diagnostics;
+
+namespace System.Collections.Generic
+{
+ // LargeArrayBuilder.netcoreapp.cs provides a "LargeArrayBuilder" that's meant to help
+ // avoid allocations and copying while building up an array. But in doing so, it utilizes
+ // T[][] to store T[]s, which results in significant size increases for AOT builds. To
+ // address that, this minimal wrapper for ArrayBuilder<T> may be used instead; it's a simple
+ // passthrough to ArrayBuilder<T>, and thus doesn't incur the size increase due to the T[][]s.
+
+ internal struct LargeArrayBuilder<T>
+ {
+ private ArrayBuilder<T> _builder; // mutable struct; do not make this readonly
+
+ public LargeArrayBuilder(bool initialize) : this()
+ {
+ // This is a workaround for C# not having parameterless struct constructors yet.
+ // Once it gets them, replace this with a parameterless constructor.
+ Debug.Assert(initialize);
+ }
+
+ public int Count => _builder.Count;
+
+ public void Add(T item) => _builder.Add(item);
+
+ public void AddRange(IEnumerable<T> items)
+ {
+ Debug.Assert(items != null);
+ foreach (T item in items)
+ {
+ _builder.Add(item);
+ }
+ }
+
+ public void SlowAdd(T item) => _builder.Add(item);
+
+ public T[] ToArray() => _builder.ToArray();
+
+ public CopyPosition CopyTo(CopyPosition position, T[] array, int arrayIndex, int count)
+ {
+ Array.Copy(_builder.Buffer, position.Column, array, arrayIndex, count);
+ return new CopyPosition(0, position.Column + count);
+ }
+ }
+}
--- /dev/null
+// 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.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace System.Collections.Generic
+{
+ /// <summary>
+ /// Helper type for building dynamically-sized arrays while minimizing allocations and copying.
+ /// </summary>
+ /// <typeparam name="T">The element type.</typeparam>
+ internal struct LargeArrayBuilder<T>
+ {
+ private const int StartingCapacity = 4;
+ private const int ResizeLimit = 8;
+
+ private readonly int _maxCapacity; // The maximum capacity this builder can have.
+ private T[] _first; // The first buffer we store items in. Resized until ResizeLimit.
+ private ArrayBuilder<T[]> _buffers; // After ResizeLimit * 2, we store previous buffers we've filled out here.
+ private T[] _current; // Current buffer we're reading into. If _count <= ResizeLimit, this is _first.
+ private int _index; // Index into the current buffer.
+ private int _count; // Count of all of the items in this builder.
+
+ /// <summary>
+ /// Constructs a new builder.
+ /// </summary>
+ /// <param name="initialize">Pass <c>true</c>.</param>
+ public LargeArrayBuilder(bool initialize)
+ : this(maxCapacity: int.MaxValue)
+ {
+ // This is a workaround for C# not having parameterless struct constructors yet.
+ // Once it gets them, replace this with a parameterless constructor.
+ Debug.Assert(initialize);
+ }
+
+ /// <summary>
+ /// Constructs a new builder with the specified maximum capacity.
+ /// </summary>
+ /// <param name="maxCapacity">The maximum capacity this builder can have.</param>
+ /// <remarks>
+ /// Do not add more than <paramref name="maxCapacity"/> items to this builder.
+ /// </remarks>
+ public LargeArrayBuilder(int maxCapacity)
+ : this()
+ {
+ Debug.Assert(maxCapacity >= 0);
+
+ _first = _current = Array.Empty<T>();
+ _maxCapacity = maxCapacity;
+ }
+
+ /// <summary>
+ /// Gets the number of items added to the builder.
+ /// </summary>
+ public int Count => _count;
+
+ /// <summary>
+ /// Adds an item to this builder.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <remarks>
+ /// Use <see cref="Add"/> if adding to the builder is a bottleneck for your use case.
+ /// Otherwise, use <see cref="SlowAdd"/>.
+ /// </remarks>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void Add(T item)
+ {
+ Debug.Assert(_maxCapacity > _count);
+
+ int index = _index;
+ T[] current = _current;
+
+ // Must be >= and not == to enable range check elimination
+ if ((uint)index >= (uint)current.Length)
+ {
+ AddWithBufferAllocation(item);
+ }
+ else
+ {
+ current[index] = item;
+ _index = index + 1;
+ }
+
+ _count++;
+ }
+
+ // Non-inline to improve code quality as uncommon path
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void AddWithBufferAllocation(T item)
+ {
+ AllocateBuffer();
+ _current[_index++] = item;
+ }
+
+ /// <summary>
+ /// Adds a range of items to this builder.
+ /// </summary>
+ /// <param name="items">The sequence to add.</param>
+ /// <remarks>
+ /// It is the caller's responsibility to ensure that adding <paramref name="items"/>
+ /// does not cause the builder to exceed its maximum capacity.
+ /// </remarks>
+ public void AddRange(IEnumerable<T> items)
+ {
+ Debug.Assert(items != null);
+
+ using (IEnumerator<T> enumerator = items.GetEnumerator())
+ {
+ T[] destination = _current;
+ int index = _index;
+
+ // Continuously read in items from the enumerator, updating _count
+ // and _index when we run out of space.
+
+ while (enumerator.MoveNext())
+ {
+ T item = enumerator.Current;
+
+ if ((uint)index >= (uint)destination.Length)
+ {
+ AddWithBufferAllocation(item, ref destination, ref index);
+ }
+ else
+ {
+ destination[index] = item;
+ }
+
+ index++;
+ }
+
+ // Final update to _count and _index.
+ _count += index - _index;
+ _index = index;
+ }
+ }
+
+ // Non-inline to improve code quality as uncommon path
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private void AddWithBufferAllocation(T item, ref T[] destination, ref int index)
+ {
+ _count += index - _index;
+ _index = index;
+ AllocateBuffer();
+ destination = _current;
+ index = _index;
+ _current[index] = item;
+ }
+
+ /// <summary>
+ /// Copies the contents of this builder to the specified array.
+ /// </summary>
+ /// <param name="array">The destination array.</param>
+ /// <param name="arrayIndex">The index in <see cref="array"/> to start copying to.</param>
+ /// <param name="count">The number of items to copy.</param>
+ public void CopyTo(T[] array, int arrayIndex, int count)
+ {
+ Debug.Assert(arrayIndex >= 0);
+ Debug.Assert(count >= 0 && count <= Count);
+ Debug.Assert(array?.Length - arrayIndex >= count);
+
+ for (int i = 0; count > 0; i++)
+ {
+ // Find the buffer we're copying from.
+ T[] buffer = GetBuffer(index: i);
+
+ // Copy until we satisfy count, or we reach the end of the buffer.
+ int toCopy = Math.Min(count, buffer.Length);
+ Array.Copy(buffer, 0, array, arrayIndex, toCopy);
+
+ // Increment variables to that position.
+ count -= toCopy;
+ arrayIndex += toCopy;
+ }
+ }
+
+ /// <summary>
+ /// Copies the contents of this builder to the specified array.
+ /// </summary>
+ /// <param name="position">The position in this builder to start copying from.</param>
+ /// <param name="array">The destination array.</param>
+ /// <param name="arrayIndex">The index in <see cref="array"/> to start copying to.</param>
+ /// <param name="count">The number of items to copy.</param>
+ /// <returns>The position in this builder that was copied up to.</returns>
+ public CopyPosition CopyTo(CopyPosition position, T[] array, int arrayIndex, int count)
+ {
+ Debug.Assert(array != null);
+ Debug.Assert(arrayIndex >= 0);
+ Debug.Assert(count > 0 && count <= Count);
+ Debug.Assert(array.Length - arrayIndex >= count);
+
+ // Go through each buffer, which contains one 'row' of items.
+ // The index in each buffer is referred to as the 'column'.
+
+ /*
+ * Visual representation:
+ *
+ * C0 C1 C2 .. C31 .. C63
+ * R0: [0] [1] [2] .. [31]
+ * R1: [32] [33] [34] .. [63]
+ * R2: [64] [65] [66] .. [95] .. [127]
+ */
+
+ int row = position.Row;
+ int column = position.Column;
+
+ T[] buffer = GetBuffer(row);
+ int copied = CopyToCore(buffer, column);
+
+ if (count == 0)
+ {
+ return new CopyPosition(row, column + copied).Normalize(buffer.Length);
+ }
+
+ do
+ {
+ buffer = GetBuffer(++row);
+ copied = CopyToCore(buffer, 0);
+ } while (count > 0);
+
+ return new CopyPosition(row, copied).Normalize(buffer.Length);
+
+ int CopyToCore(T[] sourceBuffer, int sourceIndex)
+ {
+ Debug.Assert(sourceBuffer.Length > sourceIndex);
+
+ // Copy until we satisfy `count` or reach the end of the current buffer.
+ int copyCount = Math.Min(sourceBuffer.Length - sourceIndex, count);
+ Array.Copy(sourceBuffer, sourceIndex, array, arrayIndex, copyCount);
+
+ arrayIndex += copyCount;
+ count -= copyCount;
+
+ return copyCount;
+ }
+ }
+
+ /// <summary>
+ /// Retrieves the buffer at the specified index.
+ /// </summary>
+ /// <param name="index">The index of the buffer.</param>
+ public T[] GetBuffer(int index)
+ {
+ Debug.Assert(index >= 0 && index < _buffers.Count + 2);
+
+ return index == 0 ? _first :
+ index <= _buffers.Count ? _buffers[index - 1] :
+ _current;
+ }
+
+ /// <summary>
+ /// Adds an item to this builder.
+ /// </summary>
+ /// <param name="item">The item to add.</param>
+ /// <remarks>
+ /// Use <see cref="Add"/> if adding to the builder is a bottleneck for your use case.
+ /// Otherwise, use <see cref="SlowAdd"/>.
+ /// </remarks>
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public void SlowAdd(T item) => Add(item);
+
+ /// <summary>
+ /// Creates an array from the contents of this builder.
+ /// </summary>
+ public T[] ToArray()
+ {
+ if (TryMove(out T[] array))
+ {
+ // No resizing to do.
+ return array;
+ }
+
+ array = new T[_count];
+ CopyTo(array, 0, _count);
+ return array;
+ }
+
+ /// <summary>
+ /// Attempts to transfer this builder into an array without copying.
+ /// </summary>
+ /// <param name="array">The transferred array, if the operation succeeded.</param>
+ /// <returns><c>true</c> if the operation succeeded; otherwise, <c>false</c>.</returns>
+ public bool TryMove(out T[] array)
+ {
+ array = _first;
+ return _count == _first.Length;
+ }
+
+ private void AllocateBuffer()
+ {
+ // - On the first few adds, simply resize _first.
+ // - When we pass ResizeLimit, allocate ResizeLimit elements for _current
+ // and start reading into _current. Set _index to 0.
+ // - When _current runs out of space, add it to _buffers and repeat the
+ // above step, except with _current.Length * 2.
+ // - Make sure we never pass _maxCapacity in all of the above steps.
+
+ Debug.Assert((uint)_maxCapacity > (uint)_count);
+ Debug.Assert(_index == _current.Length, $"{nameof(AllocateBuffer)} was called, but there's more space.");
+
+ // If _count is int.MinValue, we want to go down the other path which will raise an exception.
+ if ((uint)_count < (uint)ResizeLimit)
+ {
+ // We haven't passed ResizeLimit. Resize _first, copying over the previous items.
+ Debug.Assert(_current == _first && _count == _first.Length);
+
+ int nextCapacity = Math.Min(_count == 0 ? StartingCapacity : _count * 2, _maxCapacity);
+
+ _current = new T[nextCapacity];
+ Array.Copy(_first, 0, _current, 0, _count);
+ _first = _current;
+ }
+ else
+ {
+ Debug.Assert(_maxCapacity > ResizeLimit);
+ Debug.Assert(_count == ResizeLimit ^ _current != _first);
+
+ int nextCapacity;
+ if (_count == ResizeLimit)
+ {
+ nextCapacity = ResizeLimit;
+ }
+ else
+ {
+ // Example scenario: Let's say _count == 64.
+ // Then our buffers look like this: | 8 | 8 | 16 | 32 |
+ // As you can see, our count will be just double the last buffer.
+ // Now, say _maxCapacity is 100. We will find the right amount to allocate by
+ // doing min(64, 100 - 64). The lhs represents double the last buffer,
+ // the rhs the limit minus the amount we've already allocated.
+
+ Debug.Assert(_count >= ResizeLimit * 2);
+ Debug.Assert(_count == _current.Length * 2);
+
+ _buffers.Add(_current);
+ nextCapacity = Math.Min(_count, _maxCapacity - _count);
+ }
+
+ _current = new T[nextCapacity];
+ _index = 0;
+ }
+ }
+ }
+}
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
-using System.Runtime.CompilerServices;
namespace System.Collections.Generic
{
/// </summary>
private string DebuggerDisplay => $"[{Row}, {Column}]";
}
-
- /// <summary>
- /// Helper type for building dynamically-sized arrays while minimizing allocations and copying.
- /// </summary>
- /// <typeparam name="T">The element type.</typeparam>
- internal struct LargeArrayBuilder<T>
- {
- private const int StartingCapacity = 4;
- private const int ResizeLimit = 8;
-
- private readonly int _maxCapacity; // The maximum capacity this builder can have.
- private T[] _first; // The first buffer we store items in. Resized until ResizeLimit.
- private ArrayBuilder<T[]> _buffers; // After ResizeLimit * 2, we store previous buffers we've filled out here.
- private T[] _current; // Current buffer we're reading into. If _count <= ResizeLimit, this is _first.
- private int _index; // Index into the current buffer.
- private int _count; // Count of all of the items in this builder.
-
- /// <summary>
- /// Constructs a new builder.
- /// </summary>
- /// <param name="initialize">Pass <c>true</c>.</param>
- public LargeArrayBuilder(bool initialize)
- : this(maxCapacity: int.MaxValue)
- {
- // This is a workaround for C# not having parameterless struct constructors yet.
- // Once it gets them, replace this with a parameterless constructor.
- Debug.Assert(initialize);
- }
-
- /// <summary>
- /// Constructs a new builder with the specified maximum capacity.
- /// </summary>
- /// <param name="maxCapacity">The maximum capacity this builder can have.</param>
- /// <remarks>
- /// Do not add more than <paramref name="maxCapacity"/> items to this builder.
- /// </remarks>
- public LargeArrayBuilder(int maxCapacity)
- : this()
- {
- Debug.Assert(maxCapacity >= 0);
-
- _first = _current = Array.Empty<T>();
- _maxCapacity = maxCapacity;
- }
-
- /// <summary>
- /// Gets the number of items added to the builder.
- /// </summary>
- public int Count => _count;
-
- /// <summary>
- /// Adds an item to this builder.
- /// </summary>
- /// <param name="item">The item to add.</param>
- /// <remarks>
- /// Use <see cref="Add"/> if adding to the builder is a bottleneck for your use case.
- /// Otherwise, use <see cref="SlowAdd"/>.
- /// </remarks>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Add(T item)
- {
- Debug.Assert(_maxCapacity > _count);
-
- int index = _index;
- T[] current = _current;
-
- // Must be >= and not == to enable range check elimination
- if ((uint)index >= (uint)current.Length)
- {
- AddWithBufferAllocation(item);
- }
- else
- {
- current[index] = item;
- _index = index + 1;
- }
-
- _count++;
- }
-
- // Non-inline to improve code quality as uncommon path
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void AddWithBufferAllocation(T item)
- {
- AllocateBuffer();
- _current[_index++] = item;
- }
-
- /// <summary>
- /// Adds a range of items to this builder.
- /// </summary>
- /// <param name="items">The sequence to add.</param>
- /// <remarks>
- /// It is the caller's responsibility to ensure that adding <paramref name="items"/>
- /// does not cause the builder to exceed its maximum capacity.
- /// </remarks>
- public void AddRange(IEnumerable<T> items)
- {
- Debug.Assert(items != null);
-
- using (IEnumerator<T> enumerator = items.GetEnumerator())
- {
- T[] destination = _current;
- int index = _index;
-
- // Continuously read in items from the enumerator, updating _count
- // and _index when we run out of space.
-
- while (enumerator.MoveNext())
- {
- T item = enumerator.Current;
-
- if ((uint)index >= (uint)destination.Length)
- {
- AddWithBufferAllocation(item, ref destination, ref index);
- }
- else
- {
- destination[index] = item;
- }
-
- index++;
- }
-
- // Final update to _count and _index.
- _count += index - _index;
- _index = index;
- }
- }
-
- // Non-inline to improve code quality as uncommon path
- [MethodImpl(MethodImplOptions.NoInlining)]
- private void AddWithBufferAllocation(T item, ref T[] destination, ref int index)
- {
- _count += index - _index;
- _index = index;
- AllocateBuffer();
- destination = _current;
- index = _index;
- _current[index] = item;
- }
-
- /// <summary>
- /// Copies the contents of this builder to the specified array.
- /// </summary>
- /// <param name="array">The destination array.</param>
- /// <param name="arrayIndex">The index in <see cref="array"/> to start copying to.</param>
- /// <param name="count">The number of items to copy.</param>
- public void CopyTo(T[] array, int arrayIndex, int count)
- {
- Debug.Assert(arrayIndex >= 0);
- Debug.Assert(count >= 0 && count <= Count);
- Debug.Assert(array?.Length - arrayIndex >= count);
-
- for (int i = 0; count > 0; i++)
- {
- // Find the buffer we're copying from.
- T[] buffer = GetBuffer(index: i);
-
- // Copy until we satisfy count, or we reach the end of the buffer.
- int toCopy = Math.Min(count, buffer.Length);
- Array.Copy(buffer, 0, array, arrayIndex, toCopy);
-
- // Increment variables to that position.
- count -= toCopy;
- arrayIndex += toCopy;
- }
- }
-
- /// <summary>
- /// Copies the contents of this builder to the specified array.
- /// </summary>
- /// <param name="position">The position in this builder to start copying from.</param>
- /// <param name="array">The destination array.</param>
- /// <param name="arrayIndex">The index in <see cref="array"/> to start copying to.</param>
- /// <param name="count">The number of items to copy.</param>
- /// <returns>The position in this builder that was copied up to.</returns>
- public CopyPosition CopyTo(CopyPosition position, T[] array, int arrayIndex, int count)
- {
- Debug.Assert(array != null);
- Debug.Assert(arrayIndex >= 0);
- Debug.Assert(count > 0 && count <= Count);
- Debug.Assert(array.Length - arrayIndex >= count);
-
- // Go through each buffer, which contains one 'row' of items.
- // The index in each buffer is referred to as the 'column'.
-
- /*
- * Visual representation:
- *
- * C0 C1 C2 .. C31 .. C63
- * R0: [0] [1] [2] .. [31]
- * R1: [32] [33] [34] .. [63]
- * R2: [64] [65] [66] .. [95] .. [127]
- */
-
- int row = position.Row;
- int column = position.Column;
-
- T[] buffer = GetBuffer(row);
- int copied = CopyToCore(buffer, column);
-
- if (count == 0)
- {
- return new CopyPosition(row, column + copied).Normalize(buffer.Length);
- }
-
- do
- {
- buffer = GetBuffer(++row);
- copied = CopyToCore(buffer, 0);
- } while (count > 0);
-
- return new CopyPosition(row, copied).Normalize(buffer.Length);
-
- int CopyToCore(T[] sourceBuffer, int sourceIndex)
- {
- Debug.Assert(sourceBuffer.Length > sourceIndex);
-
- // Copy until we satisfy `count` or reach the end of the current buffer.
- int copyCount = Math.Min(sourceBuffer.Length - sourceIndex, count);
- Array.Copy(sourceBuffer, sourceIndex, array, arrayIndex, copyCount);
-
- arrayIndex += copyCount;
- count -= copyCount;
-
- return copyCount;
- }
- }
-
- /// <summary>
- /// Retrieves the buffer at the specified index.
- /// </summary>
- /// <param name="index">The index of the buffer.</param>
- public T[] GetBuffer(int index)
- {
- Debug.Assert(index >= 0 && index < _buffers.Count + 2);
-
- return index == 0 ? _first :
- index <= _buffers.Count ? _buffers[index - 1] :
- _current;
- }
-
- /// <summary>
- /// Adds an item to this builder.
- /// </summary>
- /// <param name="item">The item to add.</param>
- /// <remarks>
- /// Use <see cref="Add"/> if adding to the builder is a bottleneck for your use case.
- /// Otherwise, use <see cref="SlowAdd"/>.
- /// </remarks>
- [MethodImpl(MethodImplOptions.NoInlining)]
- public void SlowAdd(T item) => Add(item);
-
- /// <summary>
- /// Creates an array from the contents of this builder.
- /// </summary>
- public T[] ToArray()
- {
- if (TryMove(out T[] array))
- {
- // No resizing to do.
- return array;
- }
-
- array = new T[_count];
- CopyTo(array, 0, _count);
- return array;
- }
-
- /// <summary>
- /// Attempts to transfer this builder into an array without copying.
- /// </summary>
- /// <param name="array">The transferred array, if the operation succeeded.</param>
- /// <returns><c>true</c> if the operation succeeded; otherwise, <c>false</c>.</returns>
- public bool TryMove(out T[] array)
- {
- array = _first;
- return _count == _first.Length;
- }
-
- private void AllocateBuffer()
- {
- // - On the first few adds, simply resize _first.
- // - When we pass ResizeLimit, allocate ResizeLimit elements for _current
- // and start reading into _current. Set _index to 0.
- // - When _current runs out of space, add it to _buffers and repeat the
- // above step, except with _current.Length * 2.
- // - Make sure we never pass _maxCapacity in all of the above steps.
-
- Debug.Assert((uint)_maxCapacity > (uint)_count);
- Debug.Assert(_index == _current.Length, $"{nameof(AllocateBuffer)} was called, but there's more space.");
-
- // If _count is int.MinValue, we want to go down the other path which will raise an exception.
- if ((uint)_count < (uint)ResizeLimit)
- {
- // We haven't passed ResizeLimit. Resize _first, copying over the previous items.
- Debug.Assert(_current == _first && _count == _first.Length);
-
- int nextCapacity = Math.Min(_count == 0 ? StartingCapacity : _count * 2, _maxCapacity);
-
- _current = new T[nextCapacity];
- Array.Copy(_first, 0, _current, 0, _count);
- _first = _current;
- }
- else
- {
- Debug.Assert(_maxCapacity > ResizeLimit);
- Debug.Assert(_count == ResizeLimit ^ _current != _first);
-
- int nextCapacity;
- if (_count == ResizeLimit)
- {
- nextCapacity = ResizeLimit;
- }
- else
- {
- // Example scenario: Let's say _count == 64.
- // Then our buffers look like this: | 8 | 8 | 16 | 32 |
- // As you can see, our count will be just double the last buffer.
- // Now, say _maxCapacity is 100. We will find the right amount to allocate by
- // doing min(64, 100 - 64). The lhs represents double the last buffer,
- // the rhs the limit minus the amount we've already allocated.
-
- Debug.Assert(_count >= ResizeLimit * 2);
- Debug.Assert(_count == _current.Length * 2);
-
- _buffers.Add(_current);
- nextCapacity = Math.Min(_count, _maxCapacity - _count);
- }
-
- _current = new T[nextCapacity];
- _index = 0;
- }
- }
- }
}
<Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.cs">
<Link>Common\System\Collections\Generic\LargeArrayBuilder.cs</Link>
</Compile>
+ <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs">
+ <Link>Common\System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)\System\IO\PathInternal.CaseSensitivity.cs">
<Link>Common\System\IO\PathInternal.CaseSensitivity.cs</Link>
</Compile>
[Theory]
[MemberData(nameof(EnumerableData))]
- public void AddAndIndexer(IEnumerable<T> seed)
- {
- // CreateBuilderFromSequence implicitly tests Add
- ArrayBuilder<T> builder = CreateBuilderFromSequence(seed);
-
- // Continuously shift the elements in the builder over
- // using the get/set indexers, until none are left.
- for (int left = builder.Count - 1; left >= 0; )
- {
- for (int i = 0; i < left; i++)
- {
- builder[i] = builder[i + 1];
- }
-
- // Nil out the slot we're no longer using
- builder[left--] = default(T);
-
- int offset = (builder.Count - 1) - left; // How much we've skipped into the enumerable
- IEnumerable<T> expected = seed.Skip(offset)
- .Concat(Enumerable.Repeat(default(T), offset)); // The count has not been changed, but slots @ the end have been nil'd out
-
- VerifyBuilderContents(expected, builder);
- }
- }
-
- [Theory]
- [MemberData(nameof(EnumerableData))]
public void ToArray(IEnumerable<T> seed)
{
ArrayBuilder<T> builder = CreateBuilderFromSequence(seed);
if (labeled.ToString().StartsWith("Enumerable.Range") || labeled.ToString().StartsWith("Partitioner"))
{
- Assert.Throws<NotSupportedException>(() => enumerator.Reset());
+ if (count > 0)
+ {
+ Assert.Throws<NotSupportedException>(() => enumerator.Reset());
+ }
+ // Reset behavior is undefined, and for count == 0, some singletons throw while others are nops.
}
else
{
if (labeled.ToString().StartsWith("Enumerable.Range") || labeled.ToString().StartsWith("Partitioner"))
{
- Assert.Throws<NotSupportedException>(() => enumerator.Reset());
+ if (count > 0)
+ {
+ Assert.Throws<NotSupportedException>(() => enumerator.Reset());
+ }
+ // Reset behavior is undefined, and for count == 0, some singletons throw while others are nops.
}
else
{
<TargetGroup>netcoreapp</TargetGroup>
</ContractProject>
</ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp'"> <!-- Optimize for speed -->
+ <Compile Include="System\Linq\AppendPrepend.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Concat.SpeedOpt.cs" />
+ <Compile Include="System\Linq\DefaultIfEmpty.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Distinct.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Enumerable.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Grouping.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Lookup.SpeedOpt.cs" />
+ <Compile Include="System\Linq\OrderedEnumerable.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Partition.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Range.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Repeat.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Reverse.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Select.SpeedOpt.cs" />
+ <Compile Include="System\Linq\SelectMany.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Skip.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Take.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Union.SpeedOpt.cs" />
+ <Compile Include="System\Linq\Where.SpeedOpt.cs" />
+ <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs">
+ <Link>System\Collections\Generic\LargeArrayBuilder.SpeedOpt.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup Condition="'$(TargetGroup)' == 'uap'"> <!-- Optimize for size -->
+ <Compile Include="System\Linq\Enumerable.SizeOpt.cs" />
+ <Compile Include="System\Linq\Skip.SizeOpt.cs" />
+ <Compile Include="System\Linq\Take.SizeOpt.cs" />
+ <Compile Include="$(CommonPath)\System\Collections\Generic\LargeArrayBuilder.SizeOpt.cs">
+ <Link>System\Collections\Generic\LargeArrayBuilder.SizeOpt.cs</Link>
+ </Compile>
+ </ItemGroup>
<ItemGroup Condition="'$(TargetGroup)' == 'netcoreapp' or '$(TargetGroup)' == 'uap'">
<Compile Include="$(CommonPath)\System\Collections\Generic\ArrayBuilder.cs">
<Link>System\Collections\Generic\ArrayBuilder.cs</Link>
<Compile Include="System\Linq\GroupJoin.cs" />
<Compile Include="System\Linq\Intersect.cs" />
<Compile Include="System\Linq\Iterator.cs" />
+ <Compile Include="System\Linq\IIListProvider.cs" />
+ <Compile Include="System\Linq\IPartition.cs" />
<Compile Include="System\Linq\Join.cs" />
<Compile Include="System\Linq\Last.cs" />
<Compile Include="System\Linq\Lookup.cs" />
<Compile Include="System\Linq\Min.cs" />
<Compile Include="System\Linq\OrderBy.cs" />
<Compile Include="System\Linq\OrderedEnumerable.cs" />
- <Compile Include="System\Linq\Partition.cs" />
<Compile Include="System\Linq\Range.cs" />
<Compile Include="System\Linq\Repeat.cs" />
<Compile Include="System\Linq\Reverse.cs" />
<Reference Include="System.Runtime" />
<Reference Include="System.Runtime.Extensions" />
</ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private abstract partial class AppendPrependIterator<TSource> : IIListProvider<TSource>
+ {
+ public abstract TSource[] ToArray();
+
+ public abstract List<TSource> ToList();
+
+ public abstract int GetCount(bool onlyIfCheap);
+ }
+
+ private partial class AppendPrepend1Iterator<TSource>
+ {
+ private TSource[] LazyToArray()
+ {
+ Debug.Assert(GetCount(onlyIfCheap: true) == -1);
+
+ var builder = new LargeArrayBuilder<TSource>(initialize: true);
+
+ if (!_appending)
+ {
+ builder.SlowAdd(_item);
+ }
+
+ builder.AddRange(_source);
+
+ if (_appending)
+ {
+ builder.SlowAdd(_item);
+ }
+
+ return builder.ToArray();
+ }
+
+ public override TSource[] ToArray()
+ {
+ int count = GetCount(onlyIfCheap: true);
+ if (count == -1)
+ {
+ return LazyToArray();
+ }
+
+ TSource[] array = new TSource[count];
+ int index;
+ if (_appending)
+ {
+ index = 0;
+ }
+ else
+ {
+ array[0] = _item;
+ index = 1;
+ }
+
+ EnumerableHelpers.Copy(_source, array, index, count - 1);
+
+ if (_appending)
+ {
+ array[array.Length - 1] = _item;
+ }
+
+ return array;
+ }
+
+ public override List<TSource> ToList()
+ {
+ int count = GetCount(onlyIfCheap: true);
+ List<TSource> list = count == -1 ? new List<TSource>() : new List<TSource>(count);
+ if (!_appending)
+ {
+ list.Add(_item);
+ }
+
+ list.AddRange(_source);
+ if (_appending)
+ {
+ list.Add(_item);
+ }
+
+ return list;
+ }
+
+ public override int GetCount(bool onlyIfCheap)
+ {
+ if (_source is IIListProvider<TSource> listProv)
+ {
+ int count = listProv.GetCount(onlyIfCheap);
+ return count == -1 ? -1 : count + 1;
+ }
+
+ return !onlyIfCheap || _source is ICollection<TSource> ? _source.Count() + 1 : -1;
+ }
+ }
+
+ private partial class AppendPrependN<TSource>
+ {
+ private TSource[] LazyToArray()
+ {
+ Debug.Assert(GetCount(onlyIfCheap: true) == -1);
+
+ var builder = new SparseArrayBuilder<TSource>(initialize: true);
+
+ if (_prepended != null)
+ {
+ builder.Reserve(_prependCount);
+ }
+
+ builder.AddRange(_source);
+
+ if (_appended != null)
+ {
+ builder.Reserve(_appendCount);
+ }
+
+ TSource[] array = builder.ToArray();
+
+ int index = 0;
+ for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
+ {
+ array[index++] = node.Item;
+ }
+
+ index = array.Length - 1;
+ for (SingleLinkedNode<TSource> node = _appended; node != null; node = node.Linked)
+ {
+ array[index--] = node.Item;
+ }
+
+ return array;
+ }
+
+ public override TSource[] ToArray()
+ {
+ int count = GetCount(onlyIfCheap: true);
+ if (count == -1)
+ {
+ return LazyToArray();
+ }
+
+ TSource[] array = new TSource[count];
+ int index = 0;
+ for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
+ {
+ array[index] = node.Item;
+ ++index;
+ }
+
+ if (_source is ICollection<TSource> sourceCollection)
+ {
+ sourceCollection.CopyTo(array, index);
+ }
+ else
+ {
+ foreach (TSource item in _source)
+ {
+ array[index] = item;
+ ++index;
+ }
+ }
+
+ index = array.Length;
+ for (SingleLinkedNode<TSource> node = _appended; node != null; node = node.Linked)
+ {
+ --index;
+ array[index] = node.Item;
+ }
+
+ return array;
+ }
+
+ public override List<TSource> ToList()
+ {
+ int count = GetCount(onlyIfCheap: true);
+ List<TSource> list = count == -1 ? new List<TSource>() : new List<TSource>(count);
+ for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
+ {
+ list.Add(node.Item);
+ }
+
+ list.AddRange(_source);
+ if (_appended != null)
+ {
+ IEnumerator<TSource> e = _appended.GetEnumerator(_appendCount);
+ while (e.MoveNext())
+ {
+ list.Add(e.Current);
+ }
+ }
+
+ return list;
+ }
+
+ public override int GetCount(bool onlyIfCheap)
+ {
+ if (_source is IIListProvider<TSource> listProv)
+ {
+ int count = listProv.GetCount(onlyIfCheap);
+ return count == -1 ? -1 : count + _appendCount + _prependCount;
+ }
+
+ return !onlyIfCheap || _source is ICollection<TSource> ? _source.Count() + _appendCount + _prependCount : -1;
+ }
+ }
+ }
+}
/// Represents the insertion of one or more items before or after an <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private abstract class AppendPrependIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private abstract partial class AppendPrependIterator<TSource> : Iterator<TSource>
{
protected readonly IEnumerable<TSource> _source;
protected IEnumerator<TSource> _enumerator;
base.Dispose();
}
-
- public abstract TSource[] ToArray();
-
- public abstract List<TSource> ToList();
-
- public abstract int GetCount(bool onlyIfCheap);
}
/// <summary>
/// Represents the insertion of an item before or after an <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private class AppendPrepend1Iterator<TSource> : AppendPrependIterator<TSource>
+ private partial class AppendPrepend1Iterator<TSource> : AppendPrependIterator<TSource>
{
private readonly TSource _item;
private readonly bool _appending;
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item).Add(item), null, prependCount: 2, appendCount: 0);
}
}
-
- private TSource[] LazyToArray()
- {
- Debug.Assert(GetCount(onlyIfCheap: true) == -1);
-
- var builder = new LargeArrayBuilder<TSource>(initialize: true);
-
- if (!_appending)
- {
- builder.SlowAdd(_item);
- }
-
- builder.AddRange(_source);
-
- if (_appending)
- {
- builder.SlowAdd(_item);
- }
-
- return builder.ToArray();
- }
-
- public override TSource[] ToArray()
- {
- int count = GetCount(onlyIfCheap: true);
- if (count == -1)
- {
- return LazyToArray();
- }
-
- TSource[] array = new TSource[count];
- int index;
- if (_appending)
- {
- index = 0;
- }
- else
- {
- array[0] = _item;
- index = 1;
- }
-
- EnumerableHelpers.Copy(_source, array, index, count - 1);
-
- if (_appending)
- {
- array[array.Length - 1] = _item;
- }
-
- return array;
- }
-
- public override List<TSource> ToList()
- {
- int count = GetCount(onlyIfCheap: true);
- List<TSource> list = count == -1 ? new List<TSource>() : new List<TSource>(count);
- if (!_appending)
- {
- list.Add(_item);
- }
-
- list.AddRange(_source);
- if (_appending)
- {
- list.Add(_item);
- }
-
- return list;
- }
-
- public override int GetCount(bool onlyIfCheap)
- {
- if (_source is IIListProvider<TSource> listProv)
- {
- int count = listProv.GetCount(onlyIfCheap);
- return count == -1 ? -1 : count + 1;
- }
-
- return !onlyIfCheap || _source is ICollection<TSource> ? _source.Count() + 1 : -1;
- }
}
/// <summary>
/// Represents the insertion of multiple items before or after an <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private class AppendPrependN<TSource> : AppendPrependIterator<TSource>
+ private partial class AppendPrependN<TSource> : AppendPrependIterator<TSource>
{
private readonly SingleLinkedNode<TSource> _prepended;
private readonly SingleLinkedNode<TSource> _appended;
var prepended = _prepended != null ? _prepended.Add(item) : new SingleLinkedNode<TSource>(item);
return new AppendPrependN<TSource>(_source, prepended, _appended, _prependCount + 1, _appendCount);
}
-
- private TSource[] LazyToArray()
- {
- Debug.Assert(GetCount(onlyIfCheap: true) == -1);
-
- var builder = new SparseArrayBuilder<TSource>(initialize: true);
-
- if (_prepended != null)
- {
- builder.Reserve(_prependCount);
- }
-
- builder.AddRange(_source);
-
- if (_appended != null)
- {
- builder.Reserve(_appendCount);
- }
-
- TSource[] array = builder.ToArray();
-
- int index = 0;
- for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
- {
- array[index++] = node.Item;
- }
-
- index = array.Length - 1;
- for (SingleLinkedNode<TSource> node = _appended; node != null; node = node.Linked)
- {
- array[index--] = node.Item;
- }
-
- return array;
- }
-
- public override TSource[] ToArray()
- {
- int count = GetCount(onlyIfCheap: true);
- if (count == -1)
- {
- return LazyToArray();
- }
-
- TSource[] array = new TSource[count];
- int index = 0;
- for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
- {
- array[index] = node.Item;
- ++index;
- }
-
- if (_source is ICollection<TSource> sourceCollection)
- {
- sourceCollection.CopyTo(array, index);
- }
- else
- {
- foreach (TSource item in _source)
- {
- array[index] = item;
- ++index;
- }
- }
-
- index = array.Length;
- for (SingleLinkedNode<TSource> node = _appended; node != null; node = node.Linked)
- {
- --index;
- array[index] = node.Item;
- }
-
- return array;
- }
-
- public override List<TSource> ToList()
- {
- int count = GetCount(onlyIfCheap: true);
- List<TSource> list = count == -1 ? new List<TSource>() : new List<TSource>(count);
- for (SingleLinkedNode<TSource> node = _prepended; node != null; node = node.Linked)
- {
- list.Add(node.Item);
- }
-
- list.AddRange(_source);
- if (_appended != null)
- {
- IEnumerator<TSource> e = _appended.GetEnumerator(_appendCount);
- while (e.MoveNext())
- {
- list.Add(e.Current);
- }
- }
-
- return list;
- }
-
- public override int GetCount(bool onlyIfCheap)
- {
- if (_source is IIListProvider<TSource> listProv)
- {
- int count = listProv.GetCount(onlyIfCheap);
- return count == -1 ? -1 : count + _appendCount + _prependCount;
- }
-
- return !onlyIfCheap || _source is ICollection<TSource> ? _source.Count() + _appendCount + _prependCount : -1;
- }
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class Concat2Iterator<TSource> : ConcatIterator<TSource>
+ {
+ public override int GetCount(bool onlyIfCheap)
+ {
+ int firstCount, secondCount;
+ if (!EnumerableHelpers.TryGetCount(_first, out firstCount))
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ firstCount = _first.Count();
+ }
+
+ if (!EnumerableHelpers.TryGetCount(_second, out secondCount))
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ secondCount = _second.Count();
+ }
+
+ return checked(firstCount + secondCount);
+ }
+
+ public override TSource[] ToArray()
+ {
+ var builder = new SparseArrayBuilder<TSource>(initialize: true);
+
+ bool reservedFirst = builder.ReserveOrAdd(_first);
+ bool reservedSecond = builder.ReserveOrAdd(_second);
+
+ TSource[] array = builder.ToArray();
+
+ if (reservedFirst)
+ {
+ Marker marker = builder.Markers.First();
+ Debug.Assert(marker.Index == 0);
+ EnumerableHelpers.Copy(_first, array, 0, marker.Count);
+ }
+
+ if (reservedSecond)
+ {
+ Marker marker = builder.Markers.Last();
+ EnumerableHelpers.Copy(_second, array, marker.Index, marker.Count);
+ }
+
+ return array;
+ }
+ }
+
+ private sealed partial class ConcatNIterator<TSource> : ConcatIterator<TSource>
+ {
+ public override int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap && !_hasOnlyCollections)
+ {
+ return -1;
+ }
+
+ int count = 0;
+ ConcatNIterator<TSource> node, previousN = this;
+
+ do
+ {
+ node = previousN;
+ IEnumerable<TSource> source = node._head;
+
+ // Enumerable.Count() handles ICollections in O(1) time, but check for them here anyway
+ // to avoid a method call because 1) they're common and 2) this code is run in a loop.
+ var collection = source as ICollection<TSource>;
+ Debug.Assert(!_hasOnlyCollections || collection != null);
+ int sourceCount = collection?.Count ?? source.Count();
+
+ checked
+ {
+ count += sourceCount;
+ }
+ }
+ while ((previousN = node.PreviousN) != null);
+
+ Debug.Assert(node._tail is Concat2Iterator<TSource>);
+ return checked(count + node._tail.GetCount(onlyIfCheap));
+ }
+
+ public override TSource[] ToArray() => _hasOnlyCollections ? PreallocatingToArray() : LazyToArray();
+
+ private TSource[] LazyToArray()
+ {
+ Debug.Assert(!_hasOnlyCollections);
+
+ var builder = new SparseArrayBuilder<TSource>(initialize: true);
+ var deferredCopies = new ArrayBuilder<int>();
+
+ for (int i = 0; ; i++)
+ {
+ // Unfortunately, we can't escape re-walking the linked list for each source, which has
+ // quadratic behavior, because we need to add the sources in order.
+ // On the bright side, the bottleneck will usually be iterating, buffering, and copying
+ // each of the enumerables, so this shouldn't be a noticeable perf hit for most scenarios.
+
+ IEnumerable<TSource> source = GetEnumerable(i);
+ if (source == null)
+ {
+ break;
+ }
+
+ if (builder.ReserveOrAdd(source))
+ {
+ deferredCopies.Add(i);
+ }
+ }
+
+ TSource[] array = builder.ToArray();
+
+ ArrayBuilder<Marker> markers = builder.Markers;
+ for (int i = 0; i < markers.Count; i++)
+ {
+ Marker marker = markers[i];
+ IEnumerable<TSource> source = GetEnumerable(deferredCopies[i]);
+ EnumerableHelpers.Copy(source, array, marker.Index, marker.Count);
+ }
+
+ return array;
+ }
+
+ private TSource[] PreallocatingToArray()
+ {
+ // If there are only ICollections in this iterator, then we can just get the count, preallocate the
+ // array, and copy them as we go. This has better time complexity than continuously re-walking the
+ // linked list via GetEnumerable, and better memory usage than buffering the collections.
+
+ Debug.Assert(_hasOnlyCollections);
+
+ int count = GetCount(onlyIfCheap: true);
+ Debug.Assert(count >= 0);
+
+ if (count == 0)
+ {
+ return Array.Empty<TSource>();
+ }
+
+ var array = new TSource[count];
+ int arrayIndex = array.Length; // We start copying in collection-sized chunks from the end of the array.
+
+ ConcatNIterator<TSource> node, previousN = this;
+ do
+ {
+ node = previousN;
+ ICollection<TSource> source = (ICollection<TSource>)node._head;
+ int sourceCount = source.Count;
+ if (sourceCount > 0)
+ {
+ checked
+ {
+ arrayIndex -= sourceCount;
+ }
+ source.CopyTo(array, arrayIndex);
+ }
+ }
+ while ((previousN = node.PreviousN) != null);
+
+ var previous2 = (Concat2Iterator<TSource>)node._tail;
+ var second = (ICollection<TSource>)previous2._second;
+ int secondCount = second.Count;
+
+ if (secondCount > 0)
+ {
+ second.CopyTo(array, checked(arrayIndex - secondCount));
+ }
+
+ if (arrayIndex > secondCount)
+ {
+ var first = (ICollection<TSource>)previous2._first;
+ first.CopyTo(array, 0);
+ }
+
+ return array;
+ }
+ }
+
+ private abstract partial class ConcatIterator<TSource> : IIListProvider<TSource>
+ {
+ public abstract int GetCount(bool onlyIfCheap);
+
+ public abstract TSource[] ToArray();
+
+ public List<TSource> ToList()
+ {
+ int count = GetCount(onlyIfCheap: true);
+ var list = count != -1 ? new List<TSource>(count) : new List<TSource>();
+
+ for (int i = 0; ; i++)
+ {
+ IEnumerable<TSource> source = GetEnumerable(i);
+ if (source == null)
+ {
+ break;
+ }
+
+ list.AddRange(source);
+ }
+
+ return list;
+ }
+ }
+ }
+}
/// Represents the concatenation of two <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerables.</typeparam>
- private sealed class Concat2Iterator<TSource> : ConcatIterator<TSource>
+ private sealed partial class Concat2Iterator<TSource> : ConcatIterator<TSource>
{
/// <summary>
/// The first source to concatenate.
return new ConcatNIterator<TSource>(this, next, 2, hasOnlyCollections);
}
- public override int GetCount(bool onlyIfCheap)
- {
- int firstCount, secondCount;
- if (!EnumerableHelpers.TryGetCount(_first, out firstCount))
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- firstCount = _first.Count();
- }
-
- if (!EnumerableHelpers.TryGetCount(_second, out secondCount))
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- secondCount = _second.Count();
- }
-
- return checked(firstCount + secondCount);
- }
-
internal override IEnumerable<TSource> GetEnumerable(int index)
{
Debug.Assert(index >= 0 && index <= 2);
default: return null;
}
}
-
- public override TSource[] ToArray()
- {
- var builder = new SparseArrayBuilder<TSource>(initialize: true);
-
- bool reservedFirst = builder.ReserveOrAdd(_first);
- bool reservedSecond = builder.ReserveOrAdd(_second);
-
- TSource[] array = builder.ToArray();
-
- if (reservedFirst)
- {
- Marker marker = builder.Markers.First();
- Debug.Assert(marker.Index == 0);
- EnumerableHelpers.Copy(_first, array, 0, marker.Count);
- }
-
- if (reservedSecond)
- {
- Marker marker = builder.Markers.Last();
- EnumerableHelpers.Copy(_second, array, marker.Index, marker.Count);
- }
-
- return array;
- }
}
/// <summary>
/// would be to use an array to store all of the enumerables, but this has a much better memory profile and
/// without much additional run-time cost.
/// </remarks>
- private sealed class ConcatNIterator<TSource> : ConcatIterator<TSource>
+ private sealed partial class ConcatNIterator<TSource> : ConcatIterator<TSource>
{
/// <summary>
/// The linked list of previous sources.
return new ConcatNIterator<TSource>(this, next, _headIndex + 1, hasOnlyCollections);
}
- public override int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap && !_hasOnlyCollections)
- {
- return -1;
- }
-
- int count = 0;
- ConcatNIterator<TSource> node, previousN = this;
-
- do
- {
- node = previousN;
- IEnumerable<TSource> source = node._head;
-
- // Enumerable.Count() handles ICollections in O(1) time, but check for them here anyway
- // to avoid a method call because 1) they're common and 2) this code is run in a loop.
- var collection = source as ICollection<TSource>;
- Debug.Assert(!_hasOnlyCollections || collection != null);
- int sourceCount = collection?.Count ?? source.Count();
-
- checked
- {
- count += sourceCount;
- }
- }
- while ((previousN = node.PreviousN) != null);
-
- Debug.Assert(node._tail is Concat2Iterator<TSource>);
- return checked(count + node._tail.GetCount(onlyIfCheap));
- }
-
internal override IEnumerable<TSource> GetEnumerable(int index)
{
Debug.Assert(index >= 0);
Debug.Assert(node._tail is Concat2Iterator<TSource>);
return node._tail.GetEnumerable(index);
}
-
- public override TSource[] ToArray() => _hasOnlyCollections ? PreallocatingToArray() : LazyToArray();
-
- private TSource[] LazyToArray()
- {
- Debug.Assert(!_hasOnlyCollections);
-
- var builder = new SparseArrayBuilder<TSource>(initialize: true);
- var deferredCopies = new ArrayBuilder<int>();
-
- for (int i = 0; ; i++)
- {
- // Unfortunately, we can't escape re-walking the linked list for each source, which has
- // quadratic behavior, because we need to add the sources in order.
- // On the bright side, the bottleneck will usually be iterating, buffering, and copying
- // each of the enumerables, so this shouldn't be a noticeable perf hit for most scenarios.
-
- IEnumerable<TSource> source = GetEnumerable(i);
- if (source == null)
- {
- break;
- }
-
- if (builder.ReserveOrAdd(source))
- {
- deferredCopies.Add(i);
- }
- }
-
- TSource[] array = builder.ToArray();
-
- ArrayBuilder<Marker> markers = builder.Markers;
- for (int i = 0; i < markers.Count; i++)
- {
- Marker marker = markers[i];
- IEnumerable<TSource> source = GetEnumerable(deferredCopies[i]);
- EnumerableHelpers.Copy(source, array, marker.Index, marker.Count);
- }
-
- return array;
- }
-
- private TSource[] PreallocatingToArray()
- {
- // If there are only ICollections in this iterator, then we can just get the count, preallocate the
- // array, and copy them as we go. This has better time complexity than continuously re-walking the
- // linked list via GetEnumerable, and better memory usage than buffering the collections.
-
- Debug.Assert(_hasOnlyCollections);
-
- int count = GetCount(onlyIfCheap: true);
- Debug.Assert(count >= 0);
-
- if (count == 0)
- {
- return Array.Empty<TSource>();
- }
-
- var array = new TSource[count];
- int arrayIndex = array.Length; // We start copying in collection-sized chunks from the end of the array.
-
- ConcatNIterator<TSource> node, previousN = this;
- do
- {
- node = previousN;
- ICollection<TSource> source = (ICollection<TSource>)node._head;
- int sourceCount = source.Count;
- if (sourceCount > 0)
- {
- checked
- {
- arrayIndex -= sourceCount;
- }
- source.CopyTo(array, arrayIndex);
- }
- }
- while ((previousN = node.PreviousN) != null);
-
- var previous2 = (Concat2Iterator<TSource>)node._tail;
- var second = (ICollection<TSource>)previous2._second;
- int secondCount = second.Count;
-
- if (secondCount > 0)
- {
- second.CopyTo(array, checked(arrayIndex - secondCount));
- }
-
- if (arrayIndex > secondCount)
- {
- var first = (ICollection<TSource>)previous2._first;
- first.CopyTo(array, 0);
- }
-
- return array;
- }
}
/// <summary>
/// Represents the concatenation of two or more <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerables.</typeparam>
- private abstract class ConcatIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private abstract partial class ConcatIterator<TSource> : Iterator<TSource>
{
/// <summary>
/// The enumerator of the current source, if <see cref="MoveNext"/> has been called.
return false;
}
-
- public abstract int GetCount(bool onlyIfCheap);
-
- public abstract TSource[] ToArray();
-
- public List<TSource> ToList()
- {
- int count = GetCount(onlyIfCheap: true);
- var list = count != -1 ? new List<TSource>(count) : new List<TSource>();
-
- for (int i = 0; ; i++)
- {
- IEnumerable<TSource> source = GetEnumerable(i);
- if (source == null)
- {
- break;
- }
-
- list.AddRange(source);
- }
-
- return list;
- }
}
}
}
--- /dev/null
+// 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;
+using System.Collections.Generic;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class DefaultIfEmptyIterator<TSource> : IIListProvider<TSource>
+ {
+ public TSource[] ToArray()
+ {
+ TSource[] array = _source.ToArray();
+ return array.Length == 0 ? new[] { _default } : array;
+ }
+
+ public List<TSource> ToList()
+ {
+ List<TSource> list = _source.ToList();
+ if (list.Count == 0)
+ {
+ list.Add(_default);
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ int count;
+ if (!onlyIfCheap || _source is ICollection<TSource> || _source is ICollection)
+ {
+ count = _source.Count();
+ }
+ else
+ {
+ count = _source is IIListProvider<TSource> listProv ? listProv.GetCount(onlyIfCheap: true) : -1;
+ }
+
+ return count == 0 ? 1 : count;
+ }
+ }
+ }
+}
// 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;
using System.Collections.Generic;
using System.Diagnostics;
return new DefaultIfEmptyIterator<TSource>(source, defaultValue);
}
- private sealed class DefaultIfEmptyIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private sealed partial class DefaultIfEmptyIterator<TSource> : Iterator<TSource>
{
private readonly IEnumerable<TSource> _source;
private readonly TSource _default;
base.Dispose();
}
-
- public TSource[] ToArray()
- {
- TSource[] array = _source.ToArray();
- return array.Length == 0 ? new[] { _default } : array;
- }
-
- public List<TSource> ToList()
- {
- List<TSource> list = _source.ToList();
- if (list.Count == 0)
- {
- list.Add(_default);
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- int count;
- if (!onlyIfCheap || _source is ICollection<TSource> || _source is ICollection)
- {
- count = _source.Count();
- }
- else
- {
- count = _source is IIListProvider<TSource> listProv ? listProv.GetCount(onlyIfCheap: true) : -1;
- }
-
- return count == 0 ? 1 : count;
- }
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class DistinctIterator<TSource> : IIListProvider<TSource>
+ {
+ private Set<TSource> FillSet()
+ {
+ var set = new Set<TSource>(_comparer);
+ set.UnionWith(_source);
+ return set;
+ }
+
+ public TSource[] ToArray() => FillSet().ToArray();
+
+ public List<TSource> ToList() => FillSet().ToList();
+
+ public int GetCount(bool onlyIfCheap) => onlyIfCheap ? -1 : FillSet().Count;
+ }
+ }
+}
/// An iterator that yields the distinct values in an <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private sealed class DistinctIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private sealed partial class DistinctIterator<TSource> : Iterator<TSource>
{
private readonly IEnumerable<TSource> _source;
private readonly IEqualityComparer<TSource> _comparer;
base.Dispose();
}
-
- private Set<TSource> FillSet()
- {
- Set<TSource> set = new Set<TSource>(_comparer);
- set.UnionWith(_source);
- return set;
- }
-
- public TSource[] ToArray() => FillSet().ToArray();
-
- public List<TSource> ToList() => FillSet().ToList();
-
- public int GetCount(bool onlyIfCheap) => onlyIfCheap ? -1 : FillSet().Count;
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ public static IEnumerable<TResult> Empty<TResult>() => Array.Empty<TResult>();
+ }
+}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ public static IEnumerable<TResult> Empty<TResult>() => EmptyPartition<TResult>.Instance;
+ }
+}
public static partial class Enumerable
{
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) => source;
-
- public static IEnumerable<TResult> Empty<TResult>() => Array.Empty<TResult>();
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ internal sealed partial class GroupedResultEnumerable<TSource, TKey, TElement, TResult> : IIListProvider<TResult>
+ {
+ public TResult[] ToArray() =>
+ Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).ToArray(_resultSelector);
+
+ public List<TResult> ToList() =>
+ Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).ToList(_resultSelector);
+
+ public int GetCount(bool onlyIfCheap) =>
+ onlyIfCheap ? -1 : Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).Count;
+ }
+
+ internal sealed partial class GroupedResultEnumerable<TSource, TKey, TResult> : IIListProvider<TResult>
+ {
+ public TResult[] ToArray() =>
+ Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).ToArray(_resultSelector);
+
+ public List<TResult> ToList() =>
+ Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).ToList(_resultSelector);
+
+ public int GetCount(bool onlyIfCheap) =>
+ onlyIfCheap ? -1 : Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).Count;
+ }
+
+ internal sealed partial class GroupedEnumerable<TSource, TKey, TElement> : IIListProvider<IGrouping<TKey, TElement>>
+ {
+ public IGrouping<TKey, TElement>[] ToArray()
+ {
+ IIListProvider<IGrouping<TKey, TElement>> lookup = Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer);
+ return lookup.ToArray();
+ }
+
+ public List<IGrouping<TKey, TElement>> ToList()
+ {
+ IIListProvider<IGrouping<TKey, TElement>> lookup = Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer);
+ return lookup.ToList();
+ }
+
+ public int GetCount(bool onlyIfCheap) =>
+ onlyIfCheap ? -1 : Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).Count;
+ }
+
+ internal sealed partial class GroupedEnumerable<TSource, TKey> : IIListProvider<IGrouping<TKey, TSource>>
+ {
+ public IGrouping<TKey, TSource>[] ToArray()
+ {
+ IIListProvider<IGrouping<TKey, TSource>> lookup = Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer);
+ return lookup.ToArray();
+ }
+
+ public List<IGrouping<TKey, TSource>> ToList()
+ {
+ IIListProvider<IGrouping<TKey, TSource>> lookup = Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer);
+ return lookup.ToList();
+ }
+
+ public int GetCount(bool onlyIfCheap) =>
+ onlyIfCheap ? -1 : Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).Count;
+ }
+}
}
}
- internal sealed class GroupedResultEnumerable<TSource, TKey, TElement, TResult> : IIListProvider<TResult>
+ internal sealed partial class GroupedResultEnumerable<TSource, TKey, TElement, TResult> : IEnumerable<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TKey> _keySelector;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public TResult[] ToArray() =>
- Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).ToArray(_resultSelector);
-
- public List<TResult> ToList() =>
- Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).ToList(_resultSelector);
-
- public int GetCount(bool onlyIfCheap) =>
- onlyIfCheap ? -1 : Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).Count;
}
- internal sealed class GroupedResultEnumerable<TSource, TKey, TResult> : IIListProvider<TResult>
+ internal sealed partial class GroupedResultEnumerable<TSource, TKey, TResult> : IEnumerable<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TKey> _keySelector;
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public TResult[] ToArray() =>
- Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).ToArray(_resultSelector);
-
- public List<TResult> ToList() =>
- Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).ToList(_resultSelector);
-
- public int GetCount(bool onlyIfCheap) =>
- onlyIfCheap ? -1 : Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).Count;
}
- internal sealed class GroupedEnumerable<TSource, TKey, TElement> : IIListProvider<IGrouping<TKey, TElement>>
+ internal sealed partial class GroupedEnumerable<TSource, TKey, TElement> : IEnumerable<IGrouping<TKey, TElement>>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TKey> _keySelector;
Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public IGrouping<TKey, TElement>[] ToArray()
- {
- IIListProvider<IGrouping<TKey, TElement>> lookup = Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer);
- return lookup.ToArray();
- }
-
- public List<IGrouping<TKey, TElement>> ToList()
- {
- IIListProvider<IGrouping<TKey, TElement>> lookup = Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer);
- return lookup.ToList();
- }
-
- public int GetCount(bool onlyIfCheap) =>
- onlyIfCheap ? -1 : Lookup<TKey, TElement>.Create(_source, _keySelector, _elementSelector, _comparer).Count;
}
- internal sealed class GroupedEnumerable<TSource, TKey> : IIListProvider<IGrouping<TKey, TSource>>
+ internal sealed partial class GroupedEnumerable<TSource, TKey> : IEnumerable<IGrouping<TKey, TSource>>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TKey> _keySelector;
Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
-
- public IGrouping<TKey, TSource>[] ToArray()
- {
- IIListProvider<IGrouping<TKey, TSource>> lookup = Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer);
- return lookup.ToArray();
- }
-
- public List<IGrouping<TKey, TSource>> ToList()
- {
- IIListProvider<IGrouping<TKey, TSource>> lookup = Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer);
- return lookup.ToList();
- }
-
- public int GetCount(bool onlyIfCheap) =>
- onlyIfCheap ? -1 : Lookup<TKey, TSource>.Create(_source, _keySelector, _comparer).Count;
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ /// <summary>
+ /// An iterator that can produce an array or <see cref="List{TElement}"/> through an optimized path.
+ /// </summary>
+ internal interface IIListProvider<TElement> : IEnumerable<TElement>
+ {
+ /// <summary>
+ /// Produce an array of the sequence through an optimized path.
+ /// </summary>
+ /// <returns>The array.</returns>
+ TElement[] ToArray();
+
+ /// <summary>
+ /// Produce a <see cref="List{TElement}"/> of the sequence through an optimized path.
+ /// </summary>
+ /// <returns>The <see cref="List{TElement}"/>.</returns>
+ List<TElement> ToList();
+
+ /// <summary>
+ /// Returns the count of elements in the sequence.
+ /// </summary>
+ /// <param name="onlyIfCheap">If true then the count should only be calculated if doing
+ /// so is quick (sure or likely to be constant time), otherwise -1 should be returned.</param>
+ /// <returns>The number of elements.</returns>
+ int GetCount(bool onlyIfCheap);
+ }
+}
--- /dev/null
+// 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.
+
+namespace System.Linq
+{
+ /// <summary>
+ /// An iterator that supports random access and can produce a partial sequence of its items through an optimized path.
+ /// </summary>
+ internal interface IPartition<TElement> : IIListProvider<TElement>
+ {
+ /// <summary>
+ /// Creates a new partition that skips the specified number of elements from this sequence.
+ /// </summary>
+ /// <param name="count">The number of elements to skip.</param>
+ /// <returns>An <see cref="IPartition{TElement}"/> with the first <paramref name="count"/> items removed.</returns>
+ IPartition<TElement> Skip(int count);
+
+ /// <summary>
+ /// Creates a new partition that takes the specified number of elements from this sequence.
+ /// </summary>
+ /// <param name="count">The number of elements to take.</param>
+ /// <returns>An <see cref="IPartition{TElement}"/> with only the first <paramref name="count"/> items.</returns>
+ IPartition<TElement> Take(int count);
+
+ /// <summary>
+ /// Gets the item associated with a 0-based index in this sequence.
+ /// </summary>
+ /// <param name="index">The 0-based index to access.</param>
+ /// <param name="found"><c>true</c> if the sequence contains an element at that index, <c>false</c> otherwise.</param>
+ /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
+ TElement TryGetElementAt(int index, out bool found);
+
+ /// <summary>
+ /// Gets the first item in this sequence.
+ /// </summary>
+ /// <param name="found"><c>true</c> if the sequence contains an element, <c>false</c> otherwise.</param>
+ /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
+ TElement TryGetFirst(out bool found);
+
+ /// <summary>
+ /// Gets the last item in this sequence.
+ /// </summary>
+ /// <param name="found"><c>true</c> if the sequence contains an element, <c>false</c> otherwise.</param>
+ /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
+ TElement TryGetLast(out bool found);
+ }
+}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public partial class Lookup<TKey, TElement> : IIListProvider<IGrouping<TKey, TElement>>
+ {
+ IGrouping<TKey, TElement>[] IIListProvider<IGrouping<TKey, TElement>>.ToArray()
+ {
+ IGrouping<TKey, TElement>[] array = new IGrouping<TKey, TElement>[_count];
+ int index = 0;
+ Grouping<TKey, TElement> g = _lastGrouping;
+ if (g != null)
+ {
+ do
+ {
+ g = g._next;
+ array[index] = g;
+ ++index;
+ }
+ while (g != _lastGrouping);
+ }
+
+ return array;
+ }
+
+ internal TResult[] ToArray<TResult>(Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
+ {
+ TResult[] array = new TResult[_count];
+ int index = 0;
+ Grouping<TKey, TElement> g = _lastGrouping;
+ if (g != null)
+ {
+ do
+ {
+ g = g._next;
+ g.Trim();
+ array[index] = resultSelector(g._key, g._elements);
+ ++index;
+ }
+ while (g != _lastGrouping);
+ }
+
+ return array;
+ }
+
+ List<IGrouping<TKey, TElement>> IIListProvider<IGrouping<TKey, TElement>>.ToList()
+ {
+ List<IGrouping<TKey, TElement>> list = new List<IGrouping<TKey, TElement>>(_count);
+ Grouping<TKey, TElement> g = _lastGrouping;
+ if (g != null)
+ {
+ do
+ {
+ g = g._next;
+ list.Add(g);
+ }
+ while (g != _lastGrouping);
+ }
+
+ return list;
+ }
+
+ int IIListProvider<IGrouping<TKey, TElement>>.GetCount(bool onlyIfCheap) => _count;
+ }
+}
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(SystemLinq_LookupDebugView<,>))]
- public class Lookup<TKey, TElement> : ILookup<TKey, TElement>, IIListProvider<IGrouping<TKey, TElement>>
+ public partial class Lookup<TKey, TElement> : ILookup<TKey, TElement>
{
private readonly IEqualityComparer<TKey> _comparer;
private Grouping<TKey, TElement>[] _groupings;
return grouping;
}
- return Array.Empty<TElement>();
+ return Enumerable.Empty<TElement>();
}
}
}
}
- IGrouping<TKey, TElement>[] IIListProvider<IGrouping<TKey, TElement>>.ToArray()
- {
- IGrouping<TKey, TElement>[] array = new IGrouping<TKey, TElement>[_count];
- int index = 0;
- Grouping<TKey, TElement> g = _lastGrouping;
- if (g != null)
- {
- do
- {
- g = g._next;
- array[index] = g;
- ++index;
- }
- while (g != _lastGrouping);
- }
-
- return array;
- }
-
- internal TResult[] ToArray<TResult>(Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
- {
- TResult[] array = new TResult[_count];
- int index = 0;
- Grouping<TKey, TElement> g = _lastGrouping;
- if (g != null)
- {
- do
- {
- g = g._next;
- g.Trim();
- array[index] = resultSelector(g._key, g._elements);
- ++index;
- }
- while (g != _lastGrouping);
- }
-
- return array;
- }
-
- List<IGrouping<TKey, TElement>> IIListProvider<IGrouping<TKey, TElement>>.ToList()
- {
- List<IGrouping<TKey, TElement>> list = new List<IGrouping<TKey, TElement>>(_count);
- Grouping<TKey, TElement> g = _lastGrouping;
- if (g != null)
- {
- do
- {
- g = g._next;
- list.Add(g);
- }
- while (g != _lastGrouping);
- }
-
- return list;
- }
-
internal List<TResult> ToList<TResult>(Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
{
List<TResult> list = new List<TResult>(_count);
return list;
}
- int IIListProvider<IGrouping<TKey, TElement>>.GetCount(bool onlyIfCheap) => _count;
-
public IEnumerable<TResult> ApplyResultSelector<TResult>(Func<TKey, IEnumerable<TElement>, TResult> resultSelector)
{
Grouping<TKey, TElement> g = _lastGrouping;
--- /dev/null
+// 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;
+using System.Collections.Generic;
+
+namespace System.Linq
+{
+ internal abstract partial class OrderedEnumerable<TElement> : IPartition<TElement>
+ {
+ public TElement[] ToArray()
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+
+ int count = buffer._count;
+ if (count == 0)
+ {
+ return buffer._items;
+ }
+
+ TElement[] array = new TElement[count];
+ int[] map = SortedMap(buffer);
+ for (int i = 0; i != array.Length; i++)
+ {
+ array[i] = buffer._items[map[i]];
+ }
+
+ return array;
+ }
+
+ public List<TElement> ToList()
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+ int count = buffer._count;
+ List<TElement> list = new List<TElement>(count);
+ if (count > 0)
+ {
+ int[] map = SortedMap(buffer);
+ for (int i = 0; i != count; i++)
+ {
+ list.Add(buffer._items[map[i]]);
+ }
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (_source is IIListProvider<TElement> listProv)
+ {
+ return listProv.GetCount(onlyIfCheap);
+ }
+
+ return !onlyIfCheap || _source is ICollection<TElement> || _source is ICollection ? _source.Count() : -1;
+ }
+
+ internal TElement[] ToArray(int minIdx, int maxIdx)
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+ int count = buffer._count;
+ if (count <= minIdx)
+ {
+ return Array.Empty<TElement>();
+ }
+
+ if (count <= maxIdx)
+ {
+ maxIdx = count - 1;
+ }
+
+ if (minIdx == maxIdx)
+ {
+ return new TElement[] { GetEnumerableSorter().ElementAt(buffer._items, count, minIdx) };
+ }
+
+ int[] map = SortedMap(buffer, minIdx, maxIdx);
+ TElement[] array = new TElement[maxIdx - minIdx + 1];
+ int idx = 0;
+ while (minIdx <= maxIdx)
+ {
+ array[idx] = buffer._items[map[minIdx]];
+ ++idx;
+ ++minIdx;
+ }
+
+ return array;
+ }
+
+ internal List<TElement> ToList(int minIdx, int maxIdx)
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+ int count = buffer._count;
+ if (count <= minIdx)
+ {
+ return new List<TElement>();
+ }
+
+ if (count <= maxIdx)
+ {
+ maxIdx = count - 1;
+ }
+
+ if (minIdx == maxIdx)
+ {
+ return new List<TElement>(1) { GetEnumerableSorter().ElementAt(buffer._items, count, minIdx) };
+ }
+
+ int[] map = SortedMap(buffer, minIdx, maxIdx);
+ List<TElement> list = new List<TElement>(maxIdx - minIdx + 1);
+ while (minIdx <= maxIdx)
+ {
+ list.Add(buffer._items[map[minIdx]]);
+ ++minIdx;
+ }
+
+ return list;
+ }
+
+ internal int GetCount(int minIdx, int maxIdx, bool onlyIfCheap)
+ {
+ int count = GetCount(onlyIfCheap);
+ if (count <= 0)
+ {
+ return count;
+ }
+
+ if (count <= minIdx)
+ {
+ return 0;
+ }
+
+ return (count <= maxIdx ? count : maxIdx + 1) - minIdx;
+ }
+
+ public IPartition<TElement> Skip(int count) => new OrderedPartition<TElement>(this, count, int.MaxValue);
+
+ public IPartition<TElement> Take(int count) => new OrderedPartition<TElement>(this, 0, count - 1);
+
+ public TElement TryGetElementAt(int index, out bool found)
+ {
+ if (index == 0)
+ {
+ return TryGetFirst(out found);
+ }
+
+ if (index > 0)
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+ int count = buffer._count;
+ if (index < count)
+ {
+ found = true;
+ return GetEnumerableSorter().ElementAt(buffer._items, count, index);
+ }
+ }
+
+ found = false;
+ return default(TElement);
+ }
+
+ public TElement TryGetFirst(out bool found)
+ {
+ CachingComparer<TElement> comparer = GetComparer();
+ using (IEnumerator<TElement> e = _source.GetEnumerator())
+ {
+ if (!e.MoveNext())
+ {
+ found = false;
+ return default(TElement);
+ }
+
+ TElement value = e.Current;
+ comparer.SetElement(value);
+ while (e.MoveNext())
+ {
+ TElement x = e.Current;
+ if (comparer.Compare(x, true) < 0)
+ {
+ value = x;
+ }
+ }
+
+ found = true;
+ return value;
+ }
+ }
+
+ public TElement TryGetLast(out bool found)
+ {
+ using (IEnumerator<TElement> e = _source.GetEnumerator())
+ {
+ if (!e.MoveNext())
+ {
+ found = false;
+ return default(TElement);
+ }
+
+ CachingComparer<TElement> comparer = GetComparer();
+ TElement value = e.Current;
+ comparer.SetElement(value);
+ while (e.MoveNext())
+ {
+ TElement current = e.Current;
+ if (comparer.Compare(current, false) >= 0)
+ {
+ value = current;
+ }
+ }
+
+ found = true;
+ return value;
+ }
+ }
+
+ public TElement TryGetLast(int minIdx, int maxIdx, out bool found)
+ {
+ Buffer<TElement> buffer = new Buffer<TElement>(_source);
+ int count = buffer._count;
+ if (minIdx >= count)
+ {
+ found = false;
+ return default(TElement);
+ }
+
+ found = true;
+ return (maxIdx < count - 1) ? GetEnumerableSorter().ElementAt(buffer._items, count, maxIdx) : Last(buffer);
+ }
+
+ private TElement Last(Buffer<TElement> buffer)
+ {
+ CachingComparer<TElement> comparer = GetComparer();
+ TElement[] items = buffer._items;
+ int count = buffer._count;
+ TElement value = items[0];
+ comparer.SetElement(value);
+ for (int i = 1; i != count; ++i)
+ {
+ TElement x = items[i];
+ if (comparer.Compare(x, false) >= 0)
+ {
+ value = x;
+ }
+ }
+
+ return value;
+ }
+ }
+}
namespace System.Linq
{
- internal abstract class OrderedEnumerable<TElement> : IOrderedEnumerable<TElement>, IPartition<TElement>
+ internal abstract partial class OrderedEnumerable<TElement> : IOrderedEnumerable<TElement>
{
internal IEnumerable<TElement> _source;
}
}
- public TElement[] ToArray()
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
-
- int count = buffer._count;
- if (count == 0)
- {
- return buffer._items;
- }
-
- TElement[] array = new TElement[count];
- int[] map = SortedMap(buffer);
- for (int i = 0; i != array.Length; i++)
- {
- array[i] = buffer._items[map[i]];
- }
-
- return array;
- }
-
- public List<TElement> ToList()
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
- int count = buffer._count;
- List<TElement> list = new List<TElement>(count);
- if (count > 0)
- {
- int[] map = SortedMap(buffer);
- for (int i = 0; i != count; i++)
- {
- list.Add(buffer._items[map[i]]);
- }
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- if (_source is IIListProvider<TElement> listProv)
- {
- return listProv.GetCount(onlyIfCheap);
- }
-
- return !onlyIfCheap || _source is ICollection<TElement> || _source is ICollection ? _source.Count() : -1;
- }
-
internal IEnumerator<TElement> GetEnumerator(int minIdx, int maxIdx)
{
Buffer<TElement> buffer = new Buffer<TElement>(_source);
}
}
- internal TElement[] ToArray(int minIdx, int maxIdx)
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
- int count = buffer._count;
- if (count <= minIdx)
- {
- return Array.Empty<TElement>();
- }
-
- if (count <= maxIdx)
- {
- maxIdx = count - 1;
- }
-
- if (minIdx == maxIdx)
- {
- return new TElement[] { GetEnumerableSorter().ElementAt(buffer._items, count, minIdx) };
- }
-
- int[] map = SortedMap(buffer, minIdx, maxIdx);
- TElement[] array = new TElement[maxIdx - minIdx + 1];
- int idx = 0;
- while (minIdx <= maxIdx)
- {
- array[idx] = buffer._items[map[minIdx]];
- ++idx;
- ++minIdx;
- }
-
- return array;
- }
-
- internal List<TElement> ToList(int minIdx, int maxIdx)
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
- int count = buffer._count;
- if (count <= minIdx)
- {
- return new List<TElement>();
- }
-
- if (count <= maxIdx)
- {
- maxIdx = count - 1;
- }
-
- if (minIdx == maxIdx)
- {
- return new List<TElement>(1) { GetEnumerableSorter().ElementAt(buffer._items, count, minIdx) };
- }
-
- int[] map = SortedMap(buffer, minIdx, maxIdx);
- List<TElement> list = new List<TElement>(maxIdx - minIdx + 1);
- while (minIdx <= maxIdx)
- {
- list.Add(buffer._items[map[minIdx]]);
- ++minIdx;
- }
-
- return list;
- }
-
- internal int GetCount(int minIdx, int maxIdx, bool onlyIfCheap)
- {
- int count = GetCount(onlyIfCheap);
- if (count <= 0)
- {
- return count;
- }
-
- if (count <= minIdx)
- {
- return 0;
- }
-
- return (count <= maxIdx ? count : maxIdx + 1) - minIdx;
- }
-
private EnumerableSorter<TElement> GetEnumerableSorter() => GetEnumerableSorter(null);
internal abstract EnumerableSorter<TElement> GetEnumerableSorter(EnumerableSorter<TElement> next);
IOrderedEnumerable<TElement> IOrderedEnumerable<TElement>.CreateOrderedEnumerable<TKey>(Func<TElement, TKey> keySelector, IComparer<TKey> comparer, bool descending) =>
new OrderedEnumerable<TElement, TKey>(_source, keySelector, comparer, @descending, this);
- public IPartition<TElement> Skip(int count) => new OrderedPartition<TElement>(this, count, int.MaxValue);
-
- public IPartition<TElement> Take(int count) => new OrderedPartition<TElement>(this, 0, count - 1);
-
- public TElement TryGetElementAt(int index, out bool found)
- {
- if (index == 0)
- {
- return TryGetFirst(out found);
- }
-
- if (index > 0)
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
- int count = buffer._count;
- if (index < count)
- {
- found = true;
- return GetEnumerableSorter().ElementAt(buffer._items, count, index);
- }
- }
-
- found = false;
- return default(TElement);
- }
-
- public TElement TryGetFirst(out bool found)
- {
- CachingComparer<TElement> comparer = GetComparer();
- using (IEnumerator<TElement> e = _source.GetEnumerator())
- {
- if (!e.MoveNext())
- {
- found = false;
- return default(TElement);
- }
-
- TElement value = e.Current;
- comparer.SetElement(value);
- while (e.MoveNext())
- {
- TElement x = e.Current;
- if (comparer.Compare(x, true) < 0)
- {
- value = x;
- }
- }
-
- found = true;
- return value;
- }
- }
-
public TElement TryGetFirst(Func<TElement, bool> predicate, out bool found)
{
CachingComparer<TElement> comparer = GetComparer();
}
}
- public TElement TryGetLast(out bool found)
- {
- using (IEnumerator<TElement> e = _source.GetEnumerator())
- {
- if (!e.MoveNext())
- {
- found = false;
- return default(TElement);
- }
-
- CachingComparer<TElement> comparer = GetComparer();
- TElement value = e.Current;
- comparer.SetElement(value);
- while (e.MoveNext())
- {
- TElement current = e.Current;
- if (comparer.Compare(current, false) >= 0)
- {
- value = current;
- }
- }
-
- found = true;
- return value;
- }
- }
-
- public TElement TryGetLast(int minIdx, int maxIdx, out bool found)
- {
- Buffer<TElement> buffer = new Buffer<TElement>(_source);
- int count = buffer._count;
- if (minIdx >= count)
- {
- found = false;
- return default(TElement);
- }
-
- found = true;
- return (maxIdx < count - 1) ? GetEnumerableSorter().ElementAt(buffer._items, count, maxIdx) : Last(buffer);
- }
-
- private TElement Last(Buffer<TElement> buffer)
- {
- CachingComparer<TElement> comparer = GetComparer();
- TElement[] items = buffer._items;
- int count = buffer._count;
- TElement value = items[0];
- comparer.SetElement(value);
- for (int i = 1; i != count; ++i)
- {
- TElement x = items[i];
- if (comparer.Compare(x, false) >= 0)
- {
- value = x;
- }
- }
-
- return value;
- }
-
public TElement TryGetLast(Func<TElement, bool> predicate, out bool found)
{
CachingComparer<TElement> comparer = GetComparer();
namespace System.Linq
{
/// <summary>
- /// An iterator that can produce an array or <see cref="List{TElement}"/> through an optimized path.
- /// </summary>
- internal interface IIListProvider<TElement> : IEnumerable<TElement>
- {
- /// <summary>
- /// Produce an array of the sequence through an optimized path.
- /// </summary>
- /// <returns>The array.</returns>
- TElement[] ToArray();
-
- /// <summary>
- /// Produce a <see cref="List{TElement}"/> of the sequence through an optimized path.
- /// </summary>
- /// <returns>The <see cref="List{TElement}"/>.</returns>
- List<TElement> ToList();
-
- /// <summary>
- /// Returns the count of elements in the sequence.
- /// </summary>
- /// <param name="onlyIfCheap">If true then the count should only be calculated if doing
- /// so is quick (sure or likely to be constant time), otherwise -1 should be returned.</param>
- /// <returns>The number of elements.</returns>
- int GetCount(bool onlyIfCheap);
- }
-
- /// <summary>
- /// An iterator that supports random access and can produce a partial sequence of its items through an optimized path.
- /// </summary>
- internal interface IPartition<TElement> : IIListProvider<TElement>
- {
- /// <summary>
- /// Creates a new partition that skips the specified number of elements from this sequence.
- /// </summary>
- /// <param name="count">The number of elements to skip.</param>
- /// <returns>An <see cref="IPartition{TElement}"/> with the first <paramref name="count"/> items removed.</returns>
- IPartition<TElement> Skip(int count);
-
- /// <summary>
- /// Creates a new partition that takes the specified number of elements from this sequence.
- /// </summary>
- /// <param name="count">The number of elements to take.</param>
- /// <returns>An <see cref="IPartition{TElement}"/> with only the first <paramref name="count"/> items.</returns>
- IPartition<TElement> Take(int count);
-
- /// <summary>
- /// Gets the item associated with a 0-based index in this sequence.
- /// </summary>
- /// <param name="index">The 0-based index to access.</param>
- /// <param name="found"><c>true</c> if the sequence contains an element at that index, <c>false</c> otherwise.</param>
- /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
- TElement TryGetElementAt(int index, out bool found);
-
- /// <summary>
- /// Gets the first item in this sequence.
- /// </summary>
- /// <param name="found"><c>true</c> if the sequence contains an element, <c>false</c> otherwise.</param>
- /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
- TElement TryGetFirst(out bool found);
-
- /// <summary>
- /// Gets the last item in this sequence.
- /// </summary>
- /// <param name="found"><c>true</c> if the sequence contains an element, <c>false</c> otherwise.</param>
- /// <returns>The element if <paramref name="found"/> is <c>true</c>, otherwise, the default value of <see cref="TElement"/>.</returns>
- TElement TryGetLast(out bool found);
- }
-
- /// <summary>
/// Represents an enumerable with zero elements.
/// </summary>
/// <typeparam name="TElement">The element type.</typeparam>
[ExcludeFromCodeCoverage] // Shouldn't be called, and as undefined can return or throw anything anyway.
object IEnumerator.Current => default(TElement);
- void IEnumerator.Reset() => throw Error.NotSupported();
+ void IEnumerator.Reset()
+ {
+ // Do nothing.
+ }
void IDisposable.Dispose()
{
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class RangeIterator : IPartition<int>
+ {
+ public override IEnumerable<TResult> Select<TResult>(Func<int, TResult> selector)
+ {
+ return new SelectIPartitionIterator<int, TResult>(this, selector);
+ }
+
+ public int[] ToArray()
+ {
+ int[] array = new int[_end - _start];
+ int cur = _start;
+ for (int i = 0; i != array.Length; ++i)
+ {
+ array[i] = cur;
+ ++cur;
+ }
+
+ return array;
+ }
+
+ public List<int> ToList()
+ {
+ List<int> list = new List<int>(_end - _start);
+ for (int cur = _start; cur != _end; cur++)
+ {
+ list.Add(cur);
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap) => unchecked(_end - _start);
+
+ public IPartition<int> Skip(int count)
+ {
+ if (count >= _end - _start)
+ {
+ return EmptyPartition<int>.Instance;
+ }
+
+ return new RangeIterator(_start + count, _end - _start - count);
+ }
+
+ public IPartition<int> Take(int count)
+ {
+ int curCount = _end - _start;
+ if (count >= curCount)
+ {
+ return this;
+ }
+
+ return new RangeIterator(_start, count);
+ }
+
+ public int TryGetElementAt(int index, out bool found)
+ {
+ if (unchecked((uint)index < (uint)(_end - _start)))
+ {
+ found = true;
+ return _start + index;
+ }
+
+ found = false;
+ return 0;
+ }
+
+ public int TryGetFirst(out bool found)
+ {
+ found = true;
+ return _start;
+ }
+
+ public int TryGetLast(out bool found)
+ {
+ found = true;
+ return _end - 1;
+ }
+ }
+ }
+}
if (count == 0)
{
- return EmptyPartition<int>.Instance;
+ return Empty<int>();
}
return new RangeIterator(start, count);
/// <summary>
/// An iterator that yields a range of consecutive integers.
/// </summary>
- private sealed class RangeIterator : Iterator<int>, IPartition<int>
+ private sealed partial class RangeIterator : Iterator<int>
{
private readonly int _start;
private readonly int _end;
{
_state = -1; // Don't reset current
}
-
- public override IEnumerable<TResult> Select<TResult>(Func<int, TResult> selector)
- {
- return new SelectIPartitionIterator<int, TResult>(this, selector);
- }
-
- public int[] ToArray()
- {
- int[] array = new int[_end - _start];
- int cur = _start;
- for (int i = 0; i != array.Length; ++i)
- {
- array[i] = cur;
- ++cur;
- }
-
- return array;
- }
-
- public List<int> ToList()
- {
- List<int> list = new List<int>(_end - _start);
- for (int cur = _start; cur != _end; cur++)
- {
- list.Add(cur);
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap) => unchecked(_end - _start);
-
- public IPartition<int> Skip(int count)
- {
- if (count >= _end - _start)
- {
- return EmptyPartition<int>.Instance;
- }
-
- return new RangeIterator(_start + count, _end - _start - count);
- }
-
- public IPartition<int> Take(int count)
- {
- int curCount = _end - _start;
- if (count >= curCount)
- {
- return this;
- }
-
- return new RangeIterator(_start, count);
- }
-
- public int TryGetElementAt(int index, out bool found)
- {
- if (unchecked((uint)index < (uint)(_end - _start)))
- {
- found = true;
- return _start + index;
- }
-
- found = false;
- return 0;
- }
-
- public int TryGetFirst(out bool found)
- {
- found = true;
- return _start;
- }
-
- public int TryGetLast(out bool found)
- {
- found = true;
- return _end - 1;
- }
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class RepeatIterator<TResult> : IPartition<TResult>
+ {
+ public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
+ new SelectIPartitionIterator<TResult, TResult2>(this, selector);
+
+ public TResult[] ToArray()
+ {
+ TResult[] array = new TResult[_count];
+ if (_current != null)
+ {
+ Array.Fill(array, _current);
+ }
+
+ return array;
+ }
+
+ public List<TResult> ToList()
+ {
+ List<TResult> list = new List<TResult>(_count);
+ for (int i = 0; i != _count; ++i)
+ {
+ list.Add(_current);
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap) => _count;
+
+ public IPartition<TResult> Skip(int count)
+ {
+ if (count >= _count)
+ {
+ return EmptyPartition<TResult>.Instance;
+ }
+
+ return new RepeatIterator<TResult>(_current, _count - count);
+ }
+
+ public IPartition<TResult> Take(int count)
+ {
+ if (count >= _count)
+ {
+ return this;
+ }
+
+ return new RepeatIterator<TResult>(_current, count);
+ }
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ if ((uint)index < (uint)_count)
+ {
+ found = true;
+ return _current;
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ found = true;
+ return _current;
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ found = true;
+ return _current;
+ }
+ }
+ }
+}
if (count == 0)
{
- return EmptyPartition<TResult>.Instance;
+ return Empty<TResult>();
}
return new RepeatIterator<TResult>(element, count);
/// An iterator that yields the same item multiple times.
/// </summary>
/// <typeparam name="TResult">The type of the item.</typeparam>
- private sealed class RepeatIterator<TResult> : Iterator<TResult>, IPartition<TResult>
+ private sealed partial class RepeatIterator<TResult> : Iterator<TResult>
{
private readonly int _count;
Dispose();
return false;
}
-
- public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
- new SelectIPartitionIterator<TResult, TResult2>(this, selector);
-
- public TResult[] ToArray()
- {
- TResult[] array = new TResult[_count];
- if (_current != null)
- {
- Array.Fill(array, _current);
- }
-
- return array;
- }
-
- public List<TResult> ToList()
- {
- List<TResult> list = new List<TResult>(_count);
- for (int i = 0; i != _count; ++i)
- {
- list.Add(_current);
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap) => _count;
-
- public IPartition<TResult> Skip(int count)
- {
- if (count >= _count)
- {
- return EmptyPartition<TResult>.Instance;
- }
-
- return new RepeatIterator<TResult>(_current, _count - count);
- }
-
- public IPartition<TResult> Take(int count)
- {
- if (count >= _count)
- {
- return this;
- }
-
- return new RepeatIterator<TResult>(_current, count);
- }
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- if ((uint)index < (uint)_count)
- {
- found = true;
- return _current;
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- found = true;
- return _current;
- }
-
- public TResult TryGetLast(out bool found)
- {
- found = true;
- return _current;
- }
}
}
}
--- /dev/null
+// 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;
+using System.Collections.Generic;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class ReverseIterator<TSource> : IIListProvider<TSource>
+ {
+ public TSource[] ToArray()
+ {
+ TSource[] array = _source.ToArray();
+ Array.Reverse(array);
+ return array;
+ }
+
+ public List<TSource> ToList()
+ {
+ List<TSource> list = _source.ToList();
+ list.Reverse();
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap)
+ {
+ switch (_source)
+ {
+ case IIListProvider<TSource> listProv:
+ return listProv.GetCount(onlyIfCheap: true);
+
+ case ICollection<TSource> colT:
+ return colT.Count;
+
+ case ICollection col:
+ return col.Count;
+
+ default:
+ return -1;
+ }
+ }
+
+ return _source.Count();
+ }
+ }
+ }
+}
// 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;
using System.Collections.Generic;
using System.Diagnostics;
/// An iterator that yields the items of an <see cref="IEnumerable{TSource}"/> in reverse.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private sealed class ReverseIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private sealed partial class ReverseIterator<TSource> : Iterator<TSource>
{
private readonly IEnumerable<TSource> _source;
private TSource[] _buffer;
_buffer = null; // Just in case this ends up being long-lived, allow the memory to be reclaimed.
base.Dispose();
}
-
- public TSource[] ToArray()
- {
- TSource[] array = _source.ToArray();
- Array.Reverse(array);
- return array;
- }
-
- public List<TSource> ToList()
- {
- List<TSource> list = _source.ToList();
- list.Reverse();
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap)
- {
- switch (_source)
- {
- case IIListProvider<TSource> listProv:
- return listProv.GetCount(onlyIfCheap: true);
-
- case ICollection<TSource> colT:
- return colT.Count;
-
- case ICollection col:
- return col.Count;
-
- default:
- return -1;
- }
- }
-
- return _source.Count();
- }
}
}
}
--- /dev/null
+// 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 static System.Linq.Utilities;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ static partial void CreateSelectIPartitionIterator<TResult, TSource>(
+ Func<TSource, TResult> selector, IPartition<TSource> partition, ref IEnumerable<TResult> result)
+ {
+ result = partition is EmptyPartition<TSource> ?
+ EmptyPartition<TResult>.Instance :
+ new SelectIPartitionIterator<TSource, TResult>(partition, selector);
+ }
+
+ private sealed partial class SelectEnumerableIterator<TSource, TResult> : IIListProvider<TResult>
+ {
+ public TResult[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TResult>(initialize: true);
+
+ foreach (TSource item in _source)
+ {
+ builder.Add(_selector(item));
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TResult> ToList()
+ {
+ var list = new List<TResult>();
+
+ foreach (TSource item in _source)
+ {
+ list.Add(_selector(item));
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource item in _source)
+ {
+ _selector(item);
+ checked
+ {
+ count++;
+ }
+ }
+
+ return count;
+ }
+ }
+
+ private sealed partial class SelectArrayIterator<TSource, TResult> : IPartition<TResult>
+ {
+ public TResult[] ToArray()
+ {
+ // See assert in constructor.
+ // Since _source should never be empty, we don't check for 0/return Array.Empty.
+ Debug.Assert(_source.Length > 0);
+
+ var results = new TResult[_source.Length];
+ for (int i = 0; i < results.Length; i++)
+ {
+ results[i] = _selector(_source[i]);
+ }
+
+ return results;
+ }
+
+ public List<TResult> ToList()
+ {
+ TSource[] source = _source;
+ var results = new List<TResult>(source.Length);
+ for (int i = 0; i < source.Length; i++)
+ {
+ results.Add(_selector(source[i]));
+ }
+
+ return results;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (!onlyIfCheap)
+ {
+ foreach (TSource item in _source)
+ {
+ _selector(item);
+ }
+ }
+
+ return _source.Length;
+ }
+
+ public IPartition<TResult> Skip(int count)
+ {
+ Debug.Assert(count > 0);
+ if (count >= _source.Length)
+ {
+ return EmptyPartition<TResult>.Instance;
+ }
+
+ return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
+ }
+
+ public IPartition<TResult> Take(int count) =>
+ count >= _source.Length ? (IPartition<TResult>)this : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ if (unchecked((uint)index < (uint)_source.Length))
+ {
+ found = true;
+ return _selector(_source[index]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ Debug.Assert(_source.Length > 0); // See assert in constructor
+
+ found = true;
+ return _selector(_source[0]);
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ Debug.Assert(_source.Length > 0); // See assert in constructor
+
+ found = true;
+ return _selector(_source[_source.Length - 1]);
+ }
+ }
+
+ private sealed partial class SelectListIterator<TSource, TResult> : IPartition<TResult>
+ {
+ public TResult[] ToArray()
+ {
+ int count = _source.Count;
+ if (count == 0)
+ {
+ return Array.Empty<TResult>();
+ }
+
+ var results = new TResult[count];
+ for (int i = 0; i < results.Length; i++)
+ {
+ results[i] = _selector(_source[i]);
+ }
+
+ return results;
+ }
+
+ public List<TResult> ToList()
+ {
+ int count = _source.Count;
+ var results = new List<TResult>(count);
+ for (int i = 0; i < count; i++)
+ {
+ results.Add(_selector(_source[i]));
+ }
+
+ return results;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ int count = _source.Count;
+
+ if (!onlyIfCheap)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ _selector(_source[i]);
+ }
+ }
+
+ return count;
+ }
+
+ public IPartition<TResult> Skip(int count)
+ {
+ Debug.Assert(count > 0);
+ return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
+ }
+
+ public IPartition<TResult> Take(int count) =>
+ new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ if (unchecked((uint)index < (uint)_source.Count))
+ {
+ found = true;
+ return _selector(_source[index]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ if (_source.Count != 0)
+ {
+ found = true;
+ return _selector(_source[0]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ int len = _source.Count;
+ if (len != 0)
+ {
+ found = true;
+ return _selector(_source[len - 1]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+ }
+
+ private sealed partial class SelectIListIterator<TSource, TResult> : IPartition<TResult>
+ {
+ public TResult[] ToArray()
+ {
+ int count = _source.Count;
+ if (count == 0)
+ {
+ return Array.Empty<TResult>();
+ }
+
+ var results = new TResult[count];
+ for (int i = 0; i < results.Length; i++)
+ {
+ results[i] = _selector(_source[i]);
+ }
+
+ return results;
+ }
+
+ public List<TResult> ToList()
+ {
+ int count = _source.Count;
+ var results = new List<TResult>(count);
+ for (int i = 0; i < count; i++)
+ {
+ results.Add(_selector(_source[i]));
+ }
+
+ return results;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ int count = _source.Count;
+
+ if (!onlyIfCheap)
+ {
+ for (int i = 0; i < count; i++)
+ {
+ _selector(_source[i]);
+ }
+ }
+
+ return count;
+ }
+
+ public IPartition<TResult> Skip(int count)
+ {
+ Debug.Assert(count > 0);
+ return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
+ }
+
+ public IPartition<TResult> Take(int count) =>
+ new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ if (unchecked((uint)index < (uint)_source.Count))
+ {
+ found = true;
+ return _selector(_source[index]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ if (_source.Count != 0)
+ {
+ found = true;
+ return _selector(_source[0]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ int len = _source.Count;
+ if (len != 0)
+ {
+ found = true;
+ return _selector(_source[len - 1]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+ }
+
+ /// <summary>
+ /// An iterator that maps each item of an <see cref="IPartition{TSource}"/>.
+ /// </summary>
+ /// <typeparam name="TSource">The type of the source partition.</typeparam>
+ /// <typeparam name="TResult">The type of the mapped items.</typeparam>
+ private sealed class SelectIPartitionIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
+ {
+ private readonly IPartition<TSource> _source;
+ private readonly Func<TSource, TResult> _selector;
+ private IEnumerator<TSource> _enumerator;
+
+ public SelectIPartitionIterator(IPartition<TSource> source, Func<TSource, TResult> selector)
+ {
+ Debug.Assert(source != null);
+ Debug.Assert(selector != null);
+ _source = source;
+ _selector = selector;
+ }
+
+ public override Iterator<TResult> Clone() =>
+ new SelectIPartitionIterator<TSource, TResult>(_source, _selector);
+
+ public override bool MoveNext()
+ {
+ switch (_state)
+ {
+ case 1:
+ _enumerator = _source.GetEnumerator();
+ _state = 2;
+ goto case 2;
+ case 2:
+ if (_enumerator.MoveNext())
+ {
+ _current = _selector(_enumerator.Current);
+ return true;
+ }
+
+ Dispose();
+ break;
+ }
+
+ return false;
+ }
+
+ public override void Dispose()
+ {
+ if (_enumerator != null)
+ {
+ _enumerator.Dispose();
+ _enumerator = null;
+ }
+
+ base.Dispose();
+ }
+
+ public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
+ new SelectIPartitionIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
+
+ public IPartition<TResult> Skip(int count)
+ {
+ Debug.Assert(count > 0);
+ return new SelectIPartitionIterator<TSource, TResult>(_source.Skip(count), _selector);
+ }
+
+ public IPartition<TResult> Take(int count) =>
+ new SelectIPartitionIterator<TSource, TResult>(_source.Take(count), _selector);
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ bool sourceFound;
+ TSource input = _source.TryGetElementAt(index, out sourceFound);
+ found = sourceFound;
+ return sourceFound ? _selector(input) : default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ bool sourceFound;
+ TSource input = _source.TryGetFirst(out sourceFound);
+ found = sourceFound;
+ return sourceFound ? _selector(input) : default(TResult);
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ bool sourceFound;
+ TSource input = _source.TryGetLast(out sourceFound);
+ found = sourceFound;
+ return sourceFound ? _selector(input) : default(TResult);
+ }
+
+ private TResult[] LazyToArray()
+ {
+ Debug.Assert(_source.GetCount(onlyIfCheap: true) == -1);
+
+ var builder = new LargeArrayBuilder<TResult>(initialize: true);
+ foreach (TSource input in _source)
+ {
+ builder.Add(_selector(input));
+ }
+ return builder.ToArray();
+ }
+
+ private TResult[] PreallocatingToArray(int count)
+ {
+ Debug.Assert(count > 0);
+ Debug.Assert(count == _source.GetCount(onlyIfCheap: true));
+
+ TResult[] array = new TResult[count];
+ int index = 0;
+ foreach (TSource input in _source)
+ {
+ array[index] = _selector(input);
+ ++index;
+ }
+
+ return array;
+ }
+
+ public TResult[] ToArray()
+ {
+ int count = _source.GetCount(onlyIfCheap: true);
+ switch (count)
+ {
+ case -1:
+ return LazyToArray();
+ case 0:
+ return Array.Empty<TResult>();
+ default:
+ return PreallocatingToArray(count);
+ }
+ }
+
+ public List<TResult> ToList()
+ {
+ int count = _source.GetCount(onlyIfCheap: true);
+ List<TResult> list;
+ switch (count)
+ {
+ case -1:
+ list = new List<TResult>();
+ break;
+ case 0:
+ return new List<TResult>();
+ default:
+ list = new List<TResult>(count);
+ break;
+ }
+
+ foreach (TSource input in _source)
+ {
+ list.Add(_selector(input));
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (!onlyIfCheap)
+ {
+ foreach (TSource item in _source)
+ {
+ _selector(item);
+ }
+ }
+
+ return _source.GetCount(onlyIfCheap);
+ }
+ }
+
+ /// <summary>
+ /// An iterator that maps each item of part of an <see cref="IList{TSource}"/>.
+ /// </summary>
+ /// <typeparam name="TSource">The type of the source list.</typeparam>
+ /// <typeparam name="TResult">The type of the mapped items.</typeparam>
+ private sealed class SelectListPartitionIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
+ {
+ private readonly IList<TSource> _source;
+ private readonly Func<TSource, TResult> _selector;
+ private readonly int _minIndexInclusive;
+ private readonly int _maxIndexInclusive;
+
+ public SelectListPartitionIterator(IList<TSource> source, Func<TSource, TResult> selector, int minIndexInclusive, int maxIndexInclusive)
+ {
+ Debug.Assert(source != null);
+ Debug.Assert(selector != null);
+ Debug.Assert(minIndexInclusive >= 0);
+ Debug.Assert(minIndexInclusive <= maxIndexInclusive);
+ _source = source;
+ _selector = selector;
+ _minIndexInclusive = minIndexInclusive;
+ _maxIndexInclusive = maxIndexInclusive;
+ }
+
+ public override Iterator<TResult> Clone() =>
+ new SelectListPartitionIterator<TSource, TResult>(_source, _selector, _minIndexInclusive, _maxIndexInclusive);
+
+ public override bool MoveNext()
+ {
+ // _state - 1 represents the zero-based index into the list.
+ // Having a separate field for the index would be more readable. However, we save it
+ // into _state with a bias to minimize field size of the iterator.
+ int index = _state - 1;
+ if (unchecked((uint)index <= (uint)(_maxIndexInclusive - _minIndexInclusive) && index < _source.Count - _minIndexInclusive))
+ {
+ _current = _selector(_source[_minIndexInclusive + index]);
+ ++_state;
+ return true;
+ }
+
+ Dispose();
+ return false;
+ }
+
+ public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
+ new SelectListPartitionIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector), _minIndexInclusive, _maxIndexInclusive);
+
+ public IPartition<TResult> Skip(int count)
+ {
+ Debug.Assert(count > 0);
+ int minIndex = _minIndexInclusive + count;
+ return (uint)minIndex > (uint)_maxIndexInclusive ? EmptyPartition<TResult>.Instance : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, minIndex, _maxIndexInclusive);
+ }
+
+ public IPartition<TResult> Take(int count)
+ {
+ int maxIndex = _minIndexInclusive + count - 1;
+ return (uint)maxIndex >= (uint)_maxIndexInclusive ? this : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, _minIndexInclusive, maxIndex);
+ }
+
+ public TResult TryGetElementAt(int index, out bool found)
+ {
+ if ((uint)index <= (uint)(_maxIndexInclusive - _minIndexInclusive) && index < _source.Count - _minIndexInclusive)
+ {
+ found = true;
+ return _selector(_source[_minIndexInclusive + index]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetFirst(out bool found)
+ {
+ if (_source.Count > _minIndexInclusive)
+ {
+ found = true;
+ return _selector(_source[_minIndexInclusive]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ public TResult TryGetLast(out bool found)
+ {
+ int lastIndex = _source.Count - 1;
+ if (lastIndex >= _minIndexInclusive)
+ {
+ found = true;
+ return _selector(_source[Math.Min(lastIndex, _maxIndexInclusive)]);
+ }
+
+ found = false;
+ return default(TResult);
+ }
+
+ private int Count
+ {
+ get
+ {
+ int count = _source.Count;
+ if (count <= _minIndexInclusive)
+ {
+ return 0;
+ }
+
+ return Math.Min(count - 1, _maxIndexInclusive) - _minIndexInclusive + 1;
+ }
+ }
+
+ public TResult[] ToArray()
+ {
+ int count = Count;
+ if (count == 0)
+ {
+ return Array.Empty<TResult>();
+ }
+
+ TResult[] array = new TResult[count];
+ for (int i = 0, curIdx = _minIndexInclusive; i != array.Length; ++i, ++curIdx)
+ {
+ array[i] = _selector(_source[curIdx]);
+ }
+
+ return array;
+ }
+
+ public List<TResult> ToList()
+ {
+ int count = Count;
+ if (count == 0)
+ {
+ return new List<TResult>();
+ }
+
+ List<TResult> list = new List<TResult>(count);
+ int end = _minIndexInclusive + count;
+ for (int i = _minIndexInclusive; i != end; ++i)
+ {
+ list.Add(_selector(_source[i]));
+ }
+
+ return list;
+ }
+
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ int count = Count;
+
+ if (!onlyIfCheap)
+ {
+ int end = _minIndexInclusive + count;
+ for (int i = _minIndexInclusive; i != end; ++i)
+ {
+ _selector(_source[i]);
+ }
+ }
+
+ return count;
+ }
+ }
+ }
+}
if (source is TSource[] array)
{
return array.Length == 0 ?
- EmptyPartition<TResult>.Instance :
+ Empty<TResult>() :
new SelectArrayIterator<TSource, TResult>(array, selector);
}
if (source is IPartition<TSource> partition)
{
- return partition is EmptyPartition<TSource>
- ? EmptyPartition<TResult>.Instance
- : new SelectIPartitionIterator<TSource, TResult>(partition, selector);
+ IEnumerable<TResult> result = null;
+ CreateSelectIPartitionIterator(selector, partition, ref result);
+ if (result != null)
+ {
+ return result;
+ }
}
return new SelectEnumerableIterator<TSource, TResult>(source, selector);
}
+ static partial void CreateSelectIPartitionIterator<TResult, TSource>(
+ Func<TSource, TResult> selector, IPartition<TSource> partition, ref IEnumerable<TResult> result);
+
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
if (source == null)
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectEnumerableIterator<TSource, TResult> : Iterator<TResult>, IIListProvider<TResult>
+ private sealed partial class SelectEnumerableIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, TResult> _selector;
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectEnumerableIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- var builder = new LargeArrayBuilder<TResult>(initialize: true);
-
- foreach (TSource item in _source)
- {
- builder.Add(_selector(item));
- }
-
- return builder.ToArray();
- }
-
- public List<TResult> ToList()
- {
- var list = new List<TResult>();
-
- foreach (TSource item in _source)
- {
- list.Add(_selector(item));
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource item in _source)
- {
- _selector(item);
- checked
- {
- count++;
- }
- }
-
- return count;
- }
}
/// <summary>
/// </summary>
/// <typeparam name="TSource">The type of the source array.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectArrayIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
+ private sealed partial class SelectArrayIterator<TSource, TResult> : Iterator<TResult>
{
private readonly TSource[] _source;
private readonly Func<TSource, TResult> _selector;
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectArrayIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- // See assert in constructor.
- // Since _source should never be empty, we don't check for 0/return Array.Empty.
- Debug.Assert(_source.Length > 0);
-
- var results = new TResult[_source.Length];
- for (int i = 0; i < results.Length; i++)
- {
- results[i] = _selector(_source[i]);
- }
-
- return results;
- }
-
- public List<TResult> ToList()
- {
- TSource[] source = _source;
- var results = new List<TResult>(source.Length);
- for (int i = 0; i < source.Length; i++)
- {
- results.Add(_selector(source[i]));
- }
-
- return results;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (!onlyIfCheap)
- {
- foreach (TSource item in _source)
- {
- _selector(item);
- }
- }
-
- return _source.Length;
- }
-
- public IPartition<TResult> Skip(int count)
- {
- Debug.Assert(count > 0);
- if (count >= _source.Length)
- {
- return EmptyPartition<TResult>.Instance;
- }
-
- return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
- }
-
- public IPartition<TResult> Take(int count) =>
- count >= _source.Length ? (IPartition<TResult>)this : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- if (unchecked((uint)index < (uint)_source.Length))
- {
- found = true;
- return _selector(_source[index]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- Debug.Assert(_source.Length > 0); // See assert in constructor
-
- found = true;
- return _selector(_source[0]);
- }
-
- public TResult TryGetLast(out bool found)
- {
- Debug.Assert(_source.Length > 0); // See assert in constructor
-
- found = true;
- return _selector(_source[_source.Length - 1]);
- }
}
/// <summary>
/// </summary>
/// <typeparam name="TSource">The type of the source list.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectListIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
+ private sealed partial class SelectListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly List<TSource> _source;
private readonly Func<TSource, TResult> _selector;
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectListIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- int count = _source.Count;
- if (count == 0)
- {
- return Array.Empty<TResult>();
- }
-
- var results = new TResult[count];
- for (int i = 0; i < results.Length; i++)
- {
- results[i] = _selector(_source[i]);
- }
-
- return results;
- }
-
- public List<TResult> ToList()
- {
- int count = _source.Count;
- var results = new List<TResult>(count);
- for (int i = 0; i < count; i++)
- {
- results.Add(_selector(_source[i]));
- }
-
- return results;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- int count = _source.Count;
-
- if (!onlyIfCheap)
- {
- for (int i = 0; i < count; i++)
- {
- _selector(_source[i]);
- }
- }
-
- return count;
- }
-
- public IPartition<TResult> Skip(int count)
- {
- Debug.Assert(count > 0);
- return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
- }
-
- public IPartition<TResult> Take(int count) =>
- new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- if (unchecked((uint)index < (uint)_source.Count))
- {
- found = true;
- return _selector(_source[index]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- if (_source.Count != 0)
- {
- found = true;
- return _selector(_source[0]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetLast(out bool found)
- {
- int len = _source.Count;
- if (len != 0)
- {
- found = true;
- return _selector(_source[len - 1]);
- }
-
- found = false;
- return default(TResult);
- }
}
/// <summary>
/// </summary>
/// <typeparam name="TSource">The type of the source list.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectIListIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
+ private sealed partial class SelectIListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IList<TSource> _source;
private readonly Func<TSource, TResult> _selector;
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new SelectIListIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- int count = _source.Count;
- if (count == 0)
- {
- return Array.Empty<TResult>();
- }
-
- var results = new TResult[count];
- for (int i = 0; i < results.Length; i++)
- {
- results[i] = _selector(_source[i]);
- }
-
- return results;
- }
-
- public List<TResult> ToList()
- {
- int count = _source.Count;
- var results = new List<TResult>(count);
- for (int i = 0; i < count; i++)
- {
- results.Add(_selector(_source[i]));
- }
-
- return results;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- int count = _source.Count;
-
- if (!onlyIfCheap)
- {
- for (int i = 0; i < count; i++)
- {
- _selector(_source[i]);
- }
- }
-
- return count;
- }
-
- public IPartition<TResult> Skip(int count)
- {
- Debug.Assert(count > 0);
- return new SelectListPartitionIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
- }
-
- public IPartition<TResult> Take(int count) =>
- new SelectListPartitionIterator<TSource, TResult>(_source, _selector, 0, count - 1);
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- if (unchecked((uint)index < (uint)_source.Count))
- {
- found = true;
- return _selector(_source[index]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- if (_source.Count != 0)
- {
- found = true;
- return _selector(_source[0]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetLast(out bool found)
- {
- int len = _source.Count;
- if (len != 0)
- {
- found = true;
- return _selector(_source[len - 1]);
- }
-
- found = false;
- return default(TResult);
- }
- }
-
- /// <summary>
- /// An iterator that maps each item of an <see cref="IPartition{TSource}"/>.
- /// </summary>
- /// <typeparam name="TSource">The type of the source partition.</typeparam>
- /// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectIPartitionIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
- {
- private readonly IPartition<TSource> _source;
- private readonly Func<TSource, TResult> _selector;
- private IEnumerator<TSource> _enumerator;
-
- public SelectIPartitionIterator(IPartition<TSource> source, Func<TSource, TResult> selector)
- {
- Debug.Assert(source != null);
- Debug.Assert(selector != null);
- _source = source;
- _selector = selector;
- }
-
- public override Iterator<TResult> Clone() =>
- new SelectIPartitionIterator<TSource, TResult>(_source, _selector);
-
- public override bool MoveNext()
- {
- switch (_state)
- {
- case 1:
- _enumerator = _source.GetEnumerator();
- _state = 2;
- goto case 2;
- case 2:
- if (_enumerator.MoveNext())
- {
- _current = _selector(_enumerator.Current);
- return true;
- }
-
- Dispose();
- break;
- }
-
- return false;
- }
-
- public override void Dispose()
- {
- if (_enumerator != null)
- {
- _enumerator.Dispose();
- _enumerator = null;
- }
-
- base.Dispose();
- }
-
- public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
- new SelectIPartitionIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector));
-
- public IPartition<TResult> Skip(int count)
- {
- Debug.Assert(count > 0);
- return new SelectIPartitionIterator<TSource, TResult>(_source.Skip(count), _selector);
- }
-
- public IPartition<TResult> Take(int count) =>
- new SelectIPartitionIterator<TSource, TResult>(_source.Take(count), _selector);
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- bool sourceFound;
- TSource input = _source.TryGetElementAt(index, out sourceFound);
- found = sourceFound;
- return sourceFound ? _selector(input) : default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- bool sourceFound;
- TSource input = _source.TryGetFirst(out sourceFound);
- found = sourceFound;
- return sourceFound ? _selector(input) : default(TResult);
- }
-
- public TResult TryGetLast(out bool found)
- {
- bool sourceFound;
- TSource input = _source.TryGetLast(out sourceFound);
- found = sourceFound;
- return sourceFound ? _selector(input) : default(TResult);
- }
-
- private TResult[] LazyToArray()
- {
- Debug.Assert(_source.GetCount(onlyIfCheap: true) == -1);
-
- var builder = new LargeArrayBuilder<TResult>(initialize: true);
- foreach (TSource input in _source)
- {
- builder.Add(_selector(input));
- }
- return builder.ToArray();
- }
-
- private TResult[] PreallocatingToArray(int count)
- {
- Debug.Assert(count > 0);
- Debug.Assert(count == _source.GetCount(onlyIfCheap: true));
-
- TResult[] array = new TResult[count];
- int index = 0;
- foreach (TSource input in _source)
- {
- array[index] = _selector(input);
- ++index;
- }
-
- return array;
- }
-
- public TResult[] ToArray()
- {
- int count = _source.GetCount(onlyIfCheap: true);
- switch (count)
- {
- case -1:
- return LazyToArray();
- case 0:
- return Array.Empty<TResult>();
- default:
- return PreallocatingToArray(count);
- }
- }
-
- public List<TResult> ToList()
- {
- int count = _source.GetCount(onlyIfCheap: true);
- List<TResult> list;
- switch (count)
- {
- case -1:
- list = new List<TResult>();
- break;
- case 0:
- return new List<TResult>();
- default:
- list = new List<TResult>(count);
- break;
- }
-
- foreach (TSource input in _source)
- {
- list.Add(_selector(input));
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (!onlyIfCheap)
- {
- foreach (TSource item in _source)
- {
- _selector(item);
- }
- }
-
- return _source.GetCount(onlyIfCheap);
- }
- }
-
- /// <summary>
- /// An iterator that maps each item of part of an <see cref="IList{TSource}"/>.
- /// </summary>
- /// <typeparam name="TSource">The type of the source list.</typeparam>
- /// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class SelectListPartitionIterator<TSource, TResult> : Iterator<TResult>, IPartition<TResult>
- {
- private readonly IList<TSource> _source;
- private readonly Func<TSource, TResult> _selector;
- private readonly int _minIndexInclusive;
- private readonly int _maxIndexInclusive;
-
- public SelectListPartitionIterator(IList<TSource> source, Func<TSource, TResult> selector, int minIndexInclusive, int maxIndexInclusive)
- {
- Debug.Assert(source != null);
- Debug.Assert(selector != null);
- Debug.Assert(minIndexInclusive >= 0);
- Debug.Assert(minIndexInclusive <= maxIndexInclusive);
- _source = source;
- _selector = selector;
- _minIndexInclusive = minIndexInclusive;
- _maxIndexInclusive = maxIndexInclusive;
- }
-
- public override Iterator<TResult> Clone() =>
- new SelectListPartitionIterator<TSource, TResult>(_source, _selector, _minIndexInclusive, _maxIndexInclusive);
-
- public override bool MoveNext()
- {
- // _state - 1 represents the zero-based index into the list.
- // Having a separate field for the index would be more readable. However, we save it
- // into _state with a bias to minimize field size of the iterator.
- int index = _state - 1;
- if (unchecked((uint)index <= (uint)(_maxIndexInclusive - _minIndexInclusive) && index < _source.Count - _minIndexInclusive))
- {
- _current = _selector(_source[_minIndexInclusive + index]);
- ++_state;
- return true;
- }
-
- Dispose();
- return false;
- }
-
- public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
- new SelectListPartitionIterator<TSource, TResult2>(_source, CombineSelectors(_selector, selector), _minIndexInclusive, _maxIndexInclusive);
-
- public IPartition<TResult> Skip(int count)
- {
- Debug.Assert(count > 0);
- int minIndex = _minIndexInclusive + count;
- return (uint)minIndex > (uint)_maxIndexInclusive ? EmptyPartition<TResult>.Instance : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, minIndex, _maxIndexInclusive);
- }
-
- public IPartition<TResult> Take(int count)
- {
- int maxIndex = _minIndexInclusive + count - 1;
- return (uint)maxIndex >= (uint)_maxIndexInclusive ? this : new SelectListPartitionIterator<TSource, TResult>(_source, _selector, _minIndexInclusive, maxIndex);
- }
-
- public TResult TryGetElementAt(int index, out bool found)
- {
- if ((uint)index <= (uint)(_maxIndexInclusive - _minIndexInclusive) && index < _source.Count - _minIndexInclusive)
- {
- found = true;
- return _selector(_source[_minIndexInclusive + index]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetFirst(out bool found)
- {
- if (_source.Count > _minIndexInclusive)
- {
- found = true;
- return _selector(_source[_minIndexInclusive]);
- }
-
- found = false;
- return default(TResult);
- }
-
- public TResult TryGetLast(out bool found)
- {
- int lastIndex = _source.Count - 1;
- if (lastIndex >= _minIndexInclusive)
- {
- found = true;
- return _selector(_source[Math.Min(lastIndex, _maxIndexInclusive)]);
- }
-
- found = false;
- return default(TResult);
- }
-
- private int Count
- {
- get
- {
- int count = _source.Count;
- if (count <= _minIndexInclusive)
- {
- return 0;
- }
-
- return Math.Min(count - 1, _maxIndexInclusive) - _minIndexInclusive + 1;
- }
- }
-
- public TResult[] ToArray()
- {
- int count = Count;
- if (count == 0)
- {
- return Array.Empty<TResult>();
- }
-
- TResult[] array = new TResult[count];
- for (int i = 0, curIdx = _minIndexInclusive; i != array.Length; ++i, ++curIdx)
- {
- array[i] = _selector(_source[curIdx]);
- }
-
- return array;
- }
-
- public List<TResult> ToList()
- {
- int count = Count;
- if (count == 0)
- {
- return new List<TResult>();
- }
-
- List<TResult> list = new List<TResult>(count);
- int end = _minIndexInclusive + count;
- for (int i = _minIndexInclusive; i != end; ++i)
- {
- list.Add(_selector(_source[i]));
- }
-
- return list;
- }
-
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- int count = Count;
-
- if (!onlyIfCheap)
- {
- int end = _minIndexInclusive + count;
- for (int i = _minIndexInclusive; i != end; ++i)
- {
- _selector(_source[i]);
- }
- }
-
- return count;
- }
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class SelectManySingleSelectorIterator<TSource, TResult> : IIListProvider<TResult>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource element in _source)
+ {
+ checked
+ {
+ count += _selector(element).Count();
+ }
+ }
+
+ return count;
+ }
+
+ public TResult[] ToArray()
+ {
+ var builder = new SparseArrayBuilder<TResult>(initialize: true);
+ var deferredCopies = new ArrayBuilder<IEnumerable<TResult>>();
+
+ foreach (TSource element in _source)
+ {
+ IEnumerable<TResult> enumerable = _selector(element);
+
+ if (builder.ReserveOrAdd(enumerable))
+ {
+ deferredCopies.Add(enumerable);
+ }
+ }
+
+ TResult[] array = builder.ToArray();
+
+ ArrayBuilder<Marker> markers = builder.Markers;
+ for (int i = 0; i < markers.Count; i++)
+ {
+ Marker marker = markers[i];
+ IEnumerable<TResult> enumerable = deferredCopies[i];
+ EnumerableHelpers.Copy(enumerable, array, marker.Index, marker.Count);
+ }
+
+ return array;
+ }
+
+ public List<TResult> ToList()
+ {
+ var list = new List<TResult>();
+
+ foreach (TSource element in _source)
+ {
+ list.AddRange(_selector(element));
+ }
+
+ return list;
+ }
+ }
+ }
+}
}
}
- private sealed class SelectManySingleSelectorIterator<TSource, TResult> : Iterator<TResult>, IIListProvider<TResult>
+ private sealed partial class SelectManySingleSelectorIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, IEnumerable<TResult>> _selector;
base.Dispose();
}
- public int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource element in _source)
- {
- checked
- {
- count += _selector(element).Count();
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
switch (_state)
Dispose();
return false;
}
-
- public TResult[] ToArray()
- {
- var builder = new SparseArrayBuilder<TResult>(initialize: true);
- var deferredCopies = new ArrayBuilder<IEnumerable<TResult>>();
-
- foreach (TSource element in _source)
- {
- IEnumerable<TResult> enumerable = _selector(element);
-
- if (builder.ReserveOrAdd(enumerable))
- {
- deferredCopies.Add(enumerable);
- }
- }
-
- TResult[] array = builder.ToArray();
-
- ArrayBuilder<Marker> markers = builder.Markers;
- for (int i = 0; i < markers.Count; i++)
- {
- Marker marker = markers[i];
- IEnumerable<TResult> enumerable = deferredCopies[i];
- EnumerableHelpers.Copy(enumerable, array, marker.Index, marker.Count);
- }
-
- return array;
- }
-
- public List<TResult> ToList()
- {
- var list = new List<TResult>();
-
- foreach (TSource element in _source)
- {
- list.AddRange(_selector(element));
- }
-
- return list;
- }
}
}
}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
+ {
+ using (IEnumerator<TSource> e = source.GetEnumerator())
+ {
+ while (count > 0 && e.MoveNext()) count--;
+ if (count <= 0)
+ {
+ while (e.MoveNext()) yield return e.Current;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) =>
+ source is IList<TSource> sourceList ?
+ (IEnumerable<TSource>)new ListPartition<TSource>(sourceList, count, int.MaxValue) :
+ new EnumerablePartition<TSource>(source, count, -1);
+ }
+}
return partition.Skip(count);
}
- if (source is IList<TSource> sourceList)
- {
- return new ListPartition<TSource>(sourceList, count, int.MaxValue);
- }
-
- return new EnumerablePartition<TSource>(source, count, -1);
+ return SkipIterator(source, count);
}
public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count)
+ {
+ if (count > 0)
+ {
+ foreach (TSource element in source)
+ {
+ yield return element;
+ if (--count == 0) break;
+ }
+ }
+ }
+ }
+}
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> source, int count) =>
+ source is IPartition<TSource> partition ? partition.Take(count) :
+ source is IList<TSource> sourceList ? (IEnumerable<TSource>)new ListPartition<TSource>(sourceList, 0, count - 1) :
+ new EnumerablePartition<TSource>(source, 0, count - 1);
+ }
+}
throw Error.ArgumentNull(nameof(source));
}
- if (count <= 0)
- {
- return EmptyPartition<TSource>.Instance;
- }
-
- if (source is IPartition<TSource> partition)
- {
- return partition.Take(count);
- }
-
- if (source is IList<TSource> sourceList)
- {
- return new ListPartition<TSource>(sourceList, 0, count - 1);
- }
-
- return new EnumerablePartition<TSource>(source, 0, count - 1);
+ return count <= 0 ?
+ Empty<TSource>() :
+ TakeIterator<TSource>(source, count);
}
public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
throw Error.ArgumentNull(nameof(source));
}
- if (count <= 0)
- {
- return EmptyPartition<TSource>.Instance;
- }
-
- return TakeLastIterator(source, count);
+ return count <= 0 ?
+ Empty<TSource>() :
+ TakeLastIterator(source, count);
}
private static IEnumerable<TSource> TakeLastIterator<TSource>(IEnumerable<TSource> source, int count)
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private abstract partial class UnionIterator<TSource> : IIListProvider<TSource>
+ {
+ private Set<TSource> FillSet()
+ {
+ var set = new Set<TSource>(_comparer);
+ for (int index = 0; ; ++index)
+ {
+ IEnumerable<TSource> enumerable = GetEnumerable(index);
+ if (enumerable == null)
+ {
+ return set;
+ }
+
+ set.UnionWith(enumerable);
+ }
+ }
+
+ public TSource[] ToArray() => FillSet().ToArray();
+
+ public List<TSource> ToList() => FillSet().ToList();
+
+ public int GetCount(bool onlyIfCheap) => onlyIfCheap ? -1 : FillSet().Count;
+ }
+ }
+}
/// An iterator that yields distinct values from two or more <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerables.</typeparam>
- private abstract class UnionIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private abstract partial class UnionIterator<TSource> : Iterator<TSource>
{
internal readonly IEqualityComparer<TSource> _comparer;
private IEnumerator<TSource> _enumerator;
Dispose();
return false;
}
-
- private Set<TSource> FillSet()
- {
- Set<TSource> set = new Set<TSource>(_comparer);
- for (int index = 0; ; ++index)
- {
- IEnumerable<TSource> enumerable = GetEnumerable(index);
- if (enumerable == null)
- {
- return set;
- }
-
- set.UnionWith(enumerable);
- }
- }
-
- public TSource[] ToArray() => FillSet().ToArray();
-
- public List<TSource> ToList() => FillSet().ToList();
-
- public int GetCount(bool onlyIfCheap) => onlyIfCheap ? -1 : FillSet().Count;
}
/// <summary>
--- /dev/null
+// 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;
+
+namespace System.Linq
+{
+ public static partial class Enumerable
+ {
+ private sealed partial class WhereEnumerableIterator<TSource> : IIListProvider<TSource>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TSource[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TSource>(initialize: true);
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ builder.Add(item);
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TSource> ToList()
+ {
+ var list = new List<TSource>();
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ list.Add(item);
+ }
+ }
+
+ return list;
+ }
+ }
+
+ internal sealed partial class WhereArrayIterator<TSource> : IIListProvider<TSource>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TSource[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TSource>(_source.Length);
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ builder.Add(item);
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TSource> ToList()
+ {
+ var list = new List<TSource>();
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ list.Add(item);
+ }
+ }
+
+ return list;
+ }
+ }
+
+ private sealed partial class WhereListIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TSource[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TSource>(_source.Count);
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ builder.Add(item);
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TSource> ToList()
+ {
+ var list = new List<TSource>();
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ list.Add(item);
+ }
+ }
+
+ return list;
+ }
+ }
+
+ private sealed partial class WhereSelectArrayIterator<TSource, TResult> : IIListProvider<TResult>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ _selector(item);
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TResult[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TResult>(_source.Length);
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ builder.Add(_selector(item));
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TResult> ToList()
+ {
+ var list = new List<TResult>();
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ list.Add(_selector(item));
+ }
+ }
+
+ return list;
+ }
+ }
+
+ private sealed partial class WhereSelectListIterator<TSource, TResult> : IIListProvider<TResult>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ _selector(item);
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TResult[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TResult>(_source.Count);
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ builder.Add(_selector(item));
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TResult> ToList()
+ {
+ var list = new List<TResult>();
+
+ for (int i = 0; i < _source.Count; i++)
+ {
+ TSource item = _source[i];
+ if (_predicate(item))
+ {
+ list.Add(_selector(item));
+ }
+ }
+
+ return list;
+ }
+ }
+
+ private sealed partial class WhereSelectEnumerableIterator<TSource, TResult> : IIListProvider<TResult>
+ {
+ public int GetCount(bool onlyIfCheap)
+ {
+ // In case someone uses Count() to force evaluation of
+ // the selector, run it provided `onlyIfCheap` is false.
+
+ if (onlyIfCheap)
+ {
+ return -1;
+ }
+
+ int count = 0;
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ _selector(item);
+ checked
+ {
+ count++;
+ }
+ }
+ }
+
+ return count;
+ }
+
+ public TResult[] ToArray()
+ {
+ var builder = new LargeArrayBuilder<TResult>(initialize: true);
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ builder.Add(_selector(item));
+ }
+ }
+
+ return builder.ToArray();
+ }
+
+ public List<TResult> ToList()
+ {
+ var list = new List<TResult>();
+
+ foreach (TSource item in _source)
+ {
+ if (_predicate(item))
+ {
+ list.Add(_selector(item));
+ }
+ }
+
+ return list;
+ }
+ }
+ }
+}
if (source is TSource[] array)
{
return array.Length == 0 ?
- (IEnumerable<TSource>)EmptyPartition<TSource>.Instance :
+ Empty<TSource>() :
new WhereArrayIterator<TSource>(array, predicate);
}
/// An iterator that filters each item of an <see cref="IEnumerable{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
- private sealed class WhereEnumerableIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private sealed partial class WhereEnumerableIterator<TSource> : Iterator<TSource>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, bool> _predicate;
base.Dispose();
}
- public int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
switch (_state)
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectEnumerableIterator<TSource, TResult>(_source, _predicate, selector);
- public TSource[] ToArray()
- {
- var builder = new LargeArrayBuilder<TSource>(initialize: true);
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- builder.Add(item);
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TSource> ToList()
- {
- var list = new List<TSource>();
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- list.Add(item);
- }
- }
-
- return list;
- }
-
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereEnumerableIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
/// An iterator that filters each item of a <see cref="T:TSource[]"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source array.</typeparam>
- internal sealed class WhereArrayIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ internal sealed partial class WhereArrayIterator<TSource> : Iterator<TSource>
{
private readonly TSource[] _source;
private readonly Func<TSource, bool> _predicate;
public override Iterator<TSource> Clone() =>
new WhereArrayIterator<TSource>(_source, _predicate);
- public int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
int index = _state - 1;
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectArrayIterator<TSource, TResult>(_source, _predicate, selector);
- public TSource[] ToArray()
- {
- var builder = new LargeArrayBuilder<TSource>(_source.Length);
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- builder.Add(item);
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TSource> ToList()
- {
- var list = new List<TSource>();
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- list.Add(item);
- }
- }
-
- return list;
- }
-
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereArrayIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
/// An iterator that filters each item of a <see cref="List{TSource}"/>.
/// </summary>
/// <typeparam name="TSource">The type of the source list.</typeparam>
- private sealed class WhereListIterator<TSource> : Iterator<TSource>, IIListProvider<TSource>
+ private sealed partial class WhereListIterator<TSource> : Iterator<TSource>
{
private readonly List<TSource> _source;
private readonly Func<TSource, bool> _predicate;
public override Iterator<TSource> Clone() =>
new WhereListIterator<TSource>(_source, _predicate);
- public int GetCount(bool onlyIfCheap)
- {
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
switch (_state)
public override IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selector) =>
new WhereSelectListIterator<TSource, TResult>(_source, _predicate, selector);
- public TSource[] ToArray()
- {
- var builder = new LargeArrayBuilder<TSource>(_source.Count);
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- builder.Add(item);
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TSource> ToList()
- {
- var list = new List<TSource>();
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- list.Add(item);
- }
- }
-
- return list;
- }
-
public override IEnumerable<TSource> Where(Func<TSource, bool> predicate) =>
new WhereListIterator<TSource>(_source, CombinePredicates(_predicate, predicate));
}
/// </summary>
/// <typeparam name="TSource">The type of the source array.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class WhereSelectArrayIterator<TSource, TResult> : Iterator<TResult>, IIListProvider<TResult>
+ private sealed partial class WhereSelectArrayIterator<TSource, TResult> : Iterator<TResult>
{
private readonly TSource[] _source;
private readonly Func<TSource, bool> _predicate;
public override Iterator<TResult> Clone() =>
new WhereSelectArrayIterator<TSource, TResult>(_source, _predicate, _selector);
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- _selector(item);
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
int index = _state - 1;
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectArrayIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- var builder = new LargeArrayBuilder<TResult>(_source.Length);
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- builder.Add(_selector(item));
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TResult> ToList()
- {
- var list = new List<TResult>();
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- list.Add(_selector(item));
- }
- }
-
- return list;
- }
}
/// <summary>
/// </summary>
/// <typeparam name="TSource">The type of the source list.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class WhereSelectListIterator<TSource, TResult> : Iterator<TResult>, IIListProvider<TResult>
+ private sealed partial class WhereSelectListIterator<TSource, TResult> : Iterator<TResult>
{
private readonly List<TSource> _source;
private readonly Func<TSource, bool> _predicate;
public override Iterator<TResult> Clone() =>
new WhereSelectListIterator<TSource, TResult>(_source, _predicate, _selector);
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- _selector(item);
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
switch (_state)
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectListIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- var builder = new LargeArrayBuilder<TResult>(_source.Count);
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- builder.Add(_selector(item));
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TResult> ToList()
- {
- var list = new List<TResult>();
-
- for (int i = 0; i < _source.Count; i++)
- {
- TSource item = _source[i];
- if (_predicate(item))
- {
- list.Add(_selector(item));
- }
- }
-
- return list;
- }
}
/// <summary>
/// </summary>
/// <typeparam name="TSource">The type of the source enumerable.</typeparam>
/// <typeparam name="TResult">The type of the mapped items.</typeparam>
- private sealed class WhereSelectEnumerableIterator<TSource, TResult> : Iterator<TResult>, IIListProvider<TResult>
+ private sealed partial class WhereSelectEnumerableIterator<TSource, TResult> : Iterator<TResult>
{
private readonly IEnumerable<TSource> _source;
private readonly Func<TSource, bool> _predicate;
base.Dispose();
}
- public int GetCount(bool onlyIfCheap)
- {
- // In case someone uses Count() to force evaluation of
- // the selector, run it provided `onlyIfCheap` is false.
-
- if (onlyIfCheap)
- {
- return -1;
- }
-
- int count = 0;
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- _selector(item);
- checked
- {
- count++;
- }
- }
- }
-
- return count;
- }
-
public override bool MoveNext()
{
switch (_state)
public override IEnumerable<TResult2> Select<TResult2>(Func<TResult, TResult2> selector) =>
new WhereSelectEnumerableIterator<TSource, TResult2>(_source, _predicate, CombineSelectors(_selector, selector));
-
- public TResult[] ToArray()
- {
- var builder = new LargeArrayBuilder<TResult>(initialize: true);
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- builder.Add(_selector(item));
- }
- }
-
- return builder.ToArray();
- }
-
- public List<TResult> ToList()
- {
- var list = new List<TResult>();
-
- foreach (TSource item in _source)
- {
- if (_predicate(item))
- {
- list.Add(_selector(item));
- }
- }
-
- return list;
- }
}
}
}
// 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;
-using System.Collections.Generic;
using Xunit;
namespace System.Linq.Tests
{
Assert.Equal(new T[0], Enumerable.Empty<T>());
Assert.Equal(0, Enumerable.Empty<T>().Count());
- Assert.Same(Enumerable.Empty<T>().GetEnumerator(), ((IList<T>)Enumerable.Empty<T>()).GetEnumerator());
+ Assert.Same(Enumerable.Empty<T>().GetEnumerator(), Enumerable.Empty<T>().GetEnumerator());
}
[Fact]
TestEmptyEmpty<object>();
TestEmptyEmpty<EmptyEnumerableTest>();
}
-
- [Fact]
- public void CastToIList()
- {
- var emptyEnumerable = Enumerable.Empty<object>();
- Assert.Same(emptyEnumerable, (IList)emptyEnumerable);
- }
-
- [Fact]
- public void CastToIListGeneric()
- {
- var emptyEnumerable = Enumerable.Empty<object>();
- Assert.Same(emptyEnumerable, (IList<object>)emptyEnumerable);
- }
-
- [Fact]
- public void CastToArray()
- {
- var emptyEnumerable = Enumerable.Empty<object>();
- Assert.Same(emptyEnumerable, (object[])emptyEnumerable);
- }
}
}
}
[Fact]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core returns the instance as an optimization")]
public void SkipSame()
{
IEnumerable<int> empty = GetEmptyPartition<int>();
- // .NET Core returns the instance as an optimization.
- // see https://github.com/dotnet/corefx/pull/2401.
- Assert.Equal(!PlatformDetection.IsFullFramework, ReferenceEquals(empty, empty.Skip(2)));
+ Assert.Same(empty, empty.Skip(2));
}
[Fact]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core returns the instance as an optimization")]
public void TakeSame()
{
IEnumerable<int> empty = GetEmptyPartition<int>();
- // .NET Core returns the instance as an optimization.
- // see https://github.com/dotnet/corefx/pull/2401.
- Assert.Equal(!PlatformDetection.IsFullFramework, ReferenceEquals(empty, empty.Take(2)));
+ Assert.Same(empty, empty.Take(2));
}
[Fact]
Assert.Empty(GetEmptyPartition<int>().ToList());
}
+ [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "netfx's Take returns a compiler-generated iterator whose Reset throws.")]
[Fact]
- public void CantResetEnumerator()
+ public void ResetIsNop()
{
IEnumerator<int> en = GetEmptyPartition<int>().GetEnumerator();
- Assert.Throws<NotSupportedException>(() => en.Reset());
+ en.Reset();
+ en.Reset();
+ en.Reset();
}
}
}
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "This fails with an OOM with the full .NET Framework, as it iterates through the large array. See https://github.com/dotnet/corefx/pull/6821.")]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, "This fails with an OOM, as it iterates through the large array. See https://github.com/dotnet/corefx/pull/6821.")]
public void TakeAndSkip_DoesntIterateRangeUnlessNecessary()
{
Assert.Empty(Enumerable.Range(0, int.MaxValue).Take(int.MaxValue).OrderBy(i => i).Skip(int.MaxValue - 4).Skip(15));
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Core optimizes Enumerable.Range().Last(). Without this optimization, this test takes a long time. See https://github.com/dotnet/corefx/pull/2401.")]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core optimizes Enumerable.Range().Last(). Without this optimization, this test takes a long time. See https://github.com/dotnet/corefx/pull/2401.")]
public void Last()
{
Assert.Equal(1000000056, Enumerable.Range(57, 1000000000).Last());
}
[Fact]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Core optimizes Enumerable.Range().LastOrDefault(). Without this optimization, this test takes a long time. See https://github.com/dotnet/corefx/pull/2401.")]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core optimizes Enumerable.Range().LastOrDefault(). Without this optimization, this test takes a long time. See https://github.com/dotnet/corefx/pull/2401.")]
public void LastOrDefault()
{
Assert.Equal(int.MaxValue - 101, Enumerable.Range(-100, int.MaxValue).LastOrDefault());
}
[Theory]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Core optimizes SelectMany and throws an OverflowException. On the full .NET Framework this takes a long time. See https://github.com/dotnet/corefx/pull/13942.")]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core optimizes SelectMany and throws an OverflowException. On the full .NET Framework this takes a long time. See https://github.com/dotnet/corefx/pull/13942.")]
[InlineData(new[] { int.MaxValue, 1 })]
[InlineData(new[] { 2, int.MaxValue - 1 })]
[InlineData(new[] { 123, 456, int.MaxValue - 100000, 123456 })]
[InlineData(1000)]
[InlineData(1000000)]
[InlineData(int.MaxValue)]
- [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, ".NET Core optimizes Take(...).Skip(...) on lazy sequences to avoid unecessary allocation. Without this optimization this test takes many minutes. See https://github.com/dotnet/corefx/pull/13628.")]
+ [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, ".NET Core optimizes Take(...).Skip(...) on lazy sequences to avoid unecessary allocation. Without this optimization this test takes many minutes. See https://github.com/dotnet/corefx/pull/13628.")]
public void LazySkipAllTakenForLargeNumbers(int largeNumber)
{
Assert.Empty(new FastInfiniteEnumerator<int>().Take(largeNumber).Skip(largeNumber));