From: Stephen Toub Date: Thu, 6 Jul 2023 01:01:51 +0000 (-0400) Subject: Fix which path is taken in Enumerable.Select for empty partition (#88425) X-Git-Tag: accepted/tizen/unified/riscv/20231226.055536~1210 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b9879a79f7e2114d37c3c910a66fe305b754e64f;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Fix which path is taken in Enumerable.Select for empty partition (#88425) * Fix which path is taken in Enumerable.Select for empty partition My recent changes to improve perf of some LINQ iterators by implementing `IList` 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 --- diff --git a/src/libraries/System.Linq/src/System/Linq/Enumerable.SizeOpt.cs b/src/libraries/System.Linq/src/System/Linq/Enumerable.SizeOpt.cs index 0c37e81..bbedf34 100644 --- a/src/libraries/System.Linq/src/System/Linq/Enumerable.SizeOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Enumerable.SizeOpt.cs @@ -8,5 +8,10 @@ namespace System.Linq public static partial class Enumerable { public static IEnumerable Empty() => Array.Empty(); + + private static IEnumerable? GetEmptyIfEmpty(IEnumerable source) => + source is TSource[] { Length: 0 } ? + Array.Empty() : + null; } } diff --git a/src/libraries/System.Linq/src/System/Linq/Enumerable.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Enumerable.SpeedOpt.cs index 56c0eac..cc74d0d 100644 --- a/src/libraries/System.Linq/src/System/Linq/Enumerable.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Enumerable.SpeedOpt.cs @@ -8,5 +8,10 @@ namespace System.Linq public static partial class Enumerable { public static IEnumerable Empty() => EmptyPartition.Instance; + + private static IEnumerable? GetEmptyIfEmpty(IEnumerable source) => + source is EmptyPartition ? + EmptyPartition.Instance : + null; } } diff --git a/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs b/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs index bfa8d83..7eed584 100644 --- a/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs +++ b/src/libraries/System.Linq/src/System/Linq/Select.SpeedOpt.cs @@ -13,9 +13,7 @@ namespace System.Linq static partial void CreateSelectIPartitionIterator( Func selector, IPartition partition, ref IEnumerable? result) { - result = partition is EmptyPartition ? - EmptyPartition.Instance : - new SelectIPartitionIterator(partition, selector); + result = new SelectIPartitionIterator(partition, selector); } private sealed partial class SelectEnumerableIterator : IIListProvider diff --git a/src/libraries/System.Linq/src/System/Linq/Select.cs b/src/libraries/System.Linq/src/System/Linq/Select.cs index 9d3dcc4..403016e 100644 --- a/src/libraries/System.Linq/src/System/Linq/Select.cs +++ b/src/libraries/System.Linq/src/System/Linq/Select.cs @@ -28,6 +28,11 @@ namespace System.Linq return iterator.Select(selector); } + if (GetEmptyIfEmpty(source) is IEnumerable empty) + { + return empty; + } + if (source is IList ilist) { if (source is TSource[] array)