Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
1 change: 1 addition & 0 deletions src/libraries/System.Linq/src/System.Linq.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
<Compile Include="System\Linq\RightJoin.cs" />
<Compile Include="System\Linq\SegmentedArrayBuilder.cs" />
<Compile Include="System\Linq\Select.cs" />
<Compile Include="System\Linq\Select.SizeOpt.cs" />
<Compile Include="System\Linq\Select.SpeedOpt.cs" />
<Compile Include="System\Linq\SelectMany.cs" />
<Compile Include="System\Linq\SelectMany.SpeedOpt.cs" />
Expand Down
65 changes: 65 additions & 0 deletions src/libraries/System.Linq/src/System/Linq/Select.SizeOpt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;

namespace System.Linq
{
public static partial class Enumerable
{
private sealed class SizeOptIListSelectIterator<TSource, TResult>(IList<TSource> _source, Func<TSource, TResult> _selector)
: Iterator<TResult>
{
public override int GetCount(bool onlyIfCheap) => _source.Count;

public override Iterator<TResult> Skip(int count)
{
Debug.Assert(count > 0);
return new IListSkipTakeSelectIterator<TSource, TResult>(_source, _selector, count, int.MaxValue);
}

public override Iterator<TResult> Take(int count)
{
Debug.Assert(count > 0);
return new IListSkipTakeSelectIterator<TSource, TResult>(_source, _selector, 0, count - 1);
}

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;
}
private protected override Iterator<TResult> Clone()
=> new SizeOptIListSelectIterator<TSource, TResult>(_source, _selector);
}
}
}
4 changes: 3 additions & 1 deletion src/libraries/System.Linq/src/System/Linq/Select.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ 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)
{
return new IEnumerableSelectIterator<TSource, TResult>(iterator, selector);
return source is IList<TSource> il
? new SizeOptIListSelectIterator<TSource, TResult>(il, selector)
: new IEnumerableSelectIterator<TSource, TResult>(iterator, selector);
}
else
{
Expand Down
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 @@ -30,7 +30,7 @@ public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> sourc

count = 0;
}
else if (!IsSizeOptimized && source is Iterator<TSource> iterator)
else if (source is Iterator<TSource> iterator)
{
return iterator.Skip(count) ?? Empty<TSource>();
}
Expand Down
Loading