Skip to content

Commit

Permalink
Fix which path is taken in Enumerable.Select for empty partition (#88425
Browse files Browse the repository at this point in the history
)

* Fix which path is taken in Enumerable.Select for empty partition

My recent changes to improve perf of some LINQ iterators by implementing `IList<T>` caused Select on an empty partition to start preferring a path that wasn't optimized for empty.  This fixes it.  I searched and don't see any other operators that would be similarly negatively affected.

* Use is check
  • Loading branch information
stephentoub authored Jul 6, 2023
1 parent d510ea2 commit b9879a7
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ namespace System.Linq
public static partial class Enumerable
{
public static IEnumerable<TResult> Empty<TResult>() => Array.Empty<TResult>();

private static IEnumerable<TResult>? GetEmptyIfEmpty<TSource, TResult>(IEnumerable<TSource> source) =>
source is TSource[] { Length: 0 } ?
Array.Empty<TResult>() :
null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,10 @@ namespace System.Linq
public static partial class Enumerable
{
public static IEnumerable<TResult> Empty<TResult>() => EmptyPartition<TResult>.Instance;

private static IEnumerable<TResult>? GetEmptyIfEmpty<TSource, TResult>(IEnumerable<TSource> source) =>
source is EmptyPartition<TSource> ?
EmptyPartition<TResult>.Instance :
null;
}
}
4 changes: 1 addition & 3 deletions src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ 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);
result = new SelectIPartitionIterator<TSource, TResult>(partition, selector);
}

private sealed partial class SelectEnumerableIterator<TSource, TResult> : IIListProvider<TResult>
Expand Down
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 @@ -28,6 +28,11 @@ public static IEnumerable<TResult> Select<TSource, TResult>(
return iterator.Select(selector);
}

if (GetEmptyIfEmpty<TSource, TResult>(source) is IEnumerable<TResult> empty)
{
return empty;
}

if (source is IList<TSource> ilist)
{
if (source is TSource[] array)
Expand Down

0 comments on commit b9879a7

Please sign in to comment.