Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libraries/System.Linq/src/System.Linq.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<Compile Include="System\Linq\InfiniteSequence.cs" />
<Compile Include="System\Linq\Intersect.cs" />
<Compile Include="System\Linq\Iterator.cs" />
<Compile Include="System\Linq\Iterator.SizeOpt.cs" />
<Compile Include="System\Linq\Iterator.SpeedOpt.cs" />
<Compile Include="System\Linq\Join.cs" />
<Compile Include="System\Linq\Last.cs" />
Expand Down Expand Up @@ -70,7 +71,6 @@
<Compile Include="System\Linq\Single.cs" />
<Compile Include="System\Linq\SingleLinkedNode.cs" />
<Compile Include="System\Linq\Skip.cs" />
<Compile Include="System\Linq\Skip.SizeOpt.cs" />
<Compile Include="System\Linq\Skip.SpeedOpt.cs" />
<Compile Include="System\Linq\SkipTake.SpeedOpt.cs" />
<Compile Include="System\Linq\Sum.cs" />
Expand Down
97 changes: 97 additions & 0 deletions src/libraries/System.Linq/src/System/Linq/Iterator.SizeOpt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics;

namespace System.Linq;

public static partial class Enumerable
{
/// <summary>
/// An iterator that implements <see cref="IList{T}"/>. This is used primarily in size-optimized
/// code to turn linear-time iterators into constant-time iterators. The primary cost is
/// additional type checks, which are small compared to generic virtual calls.
/// </summary>
private sealed class SizeOptIListSelectIterator<TSource, TResult>(IList<TSource> _source, Func<TSource, TResult> _selector)
: Iterator<TResult>, IList<TResult>
{
TResult IList<TResult>.this[int index]
{
get => _selector(_source[index]);
set => ThrowHelper.ThrowNotSupportedException();
}

int ICollection<TResult>.Count => _source.Count;
bool ICollection<TResult>.IsReadOnly => true;

void ICollection<TResult>.Add(TResult item) => ThrowHelper.ThrowNotSupportedException();
void ICollection<TResult>.Clear() => ThrowHelper.ThrowNotSupportedException();
bool ICollection<TResult>.Contains(TResult item)
=> IndexOf(item) >= 0;

int IList<TResult>.IndexOf(TResult item) => IndexOf(item);

private int IndexOf(TResult item)
{
for (int i = 0; i < _source.Count; i++)
{
if (EqualityComparer<TResult>.Default.Equals(_selector(_source[i]), item))
{
return i;
}
}
return -1;
}

void ICollection<TResult>.CopyTo(TResult[] array, int arrayIndex)
{
for (int i = 0; i < _source.Count; i++)
{
array[arrayIndex + i] = _selector(_source[i]);
}
}

void IList<TResult>.Insert(int index, TResult item) => ThrowHelper.ThrowNotSupportedException();
bool ICollection<TResult>.Remove(TResult item) => ThrowHelper.ThrowNotSupportedException_Boolean();
void IList<TResult>.RemoveAt(int index) => ThrowHelper.ThrowNotSupportedException();

private protected override Iterator<TResult> Clone()
=> new SizeOptIListSelectIterator<TSource, TResult>(_source, _selector);

public override bool MoveNext()
{
var source = _source;
int index = _state - 1;
if ((uint)index < (uint)source.Count)
{
_state++;
_current = _selector(source[index]);
return true;
}

Dispose();
return false;
}

public override TResult[] ToArray()
{
TResult[] array = new TResult[_source.Count];
for (int i = 0; i < _source.Count; i++)
{
array[i] = _selector(_source[i]);
}
return array;
}
public override List<TResult> ToList()
{
List<TResult> list = new List<TResult>(_source.Count);
for (int i = 0; i < _source.Count; i++)
{
list.Add(_selector(_source[i]));
}
return list;
}
public override int GetCount(bool onlyIfCheap) => _source.Count;
}
}
5 changes: 5 additions & 0 deletions src/libraries/System.Linq/src/System/Linq/Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices.Marshalling;
using static System.Linq.Utilities;

namespace System.Linq
Expand Down Expand Up @@ -32,6 +33,10 @@ public static IEnumerable<TResult> Select<TSource, TResult>(
// don't need more code, just more data structures describing the new types).
if (IsSizeOptimized && typeof(TResult).IsValueType)
{
if (source is IList<TSource> il)
{
return new SizeOptIListSelectIterator<TSource, TResult>(il, selector);
}
return new IEnumerableSelectIterator<TSource, TResult>(iterator, selector);
}
else
Expand Down
20 changes: 0 additions & 20 deletions src/libraries/System.Linq/src/System/Linq/Skip.SizeOpt.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/libraries/System.Linq/src/System/Linq/Skip.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> sourc
return iterator.Skip(count) ?? Empty<TSource>();
}

return IsSizeOptimized ? SizeOptimizedSkipIterator(source, count) : SpeedOptimizedSkipIterator(source, count);
return SpeedOptimizedSkipIterator(source, count);
}

public static IEnumerable<TSource> SkipWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
Expand Down
11 changes: 0 additions & 11 deletions src/libraries/System.Linq/src/System/Linq/Take.SizeOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,6 @@ namespace System.Linq
{
public static partial class Enumerable
{
private static IEnumerable<TSource> SizeOptimizedTakeIterator<TSource>(IEnumerable<TSource> source, int count)
{
Debug.Assert(count > 0);

foreach (TSource element in source)
{
yield return element;
if (--count == 0) break;
}
}

private static IEnumerable<TSource> SizeOptimizedTakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
{
Debug.Assert(source is not null);
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Linq/src/System/Linq/Take.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public static IEnumerable<TSource> Take<TSource>(this IEnumerable<TSource> sourc
return [];
}

return IsSizeOptimized ? SizeOptimizedTakeIterator(source, count) : SpeedOptimizedTakeIterator(source, count);
return SpeedOptimizedTakeIterator(source, count);
}

/// <summary>Returns a specified range of contiguous elements from a sequence.</summary>
Expand Down
Loading