Skip to content

Commit ce5af20

Browse files
wip
1 parent c5bb505 commit ce5af20

File tree

11 files changed

+80
-15
lines changed

11 files changed

+80
-15
lines changed

src/libraries/System.Linq/src/System/Linq/AnyAll.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static bool Any<TSource>(this IEnumerable<TSource> source)
2121
}
2222

2323
#if !OPTIMIZE_FOR_SIZE
24-
if (source is Iterator<TSource> iterator)
24+
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
2525
{
2626
int count = iterator.GetCount(onlyIfCheap: true);
2727
if (count >= 0)

src/libraries/System.Linq/src/System/Linq/Count.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static int Count<TSource>(this IEnumerable<TSource> source)
2121
}
2222

2323
#if !OPTIMIZE_FOR_SIZE
24-
if (source is Iterator<TSource> iterator)
24+
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
2525
{
2626
return iterator.GetCount(onlyIfCheap: false);
2727
}
@@ -116,7 +116,7 @@ public static bool TryGetNonEnumeratedCount<TSource>(this IEnumerable<TSource> s
116116
}
117117

118118
#if !OPTIMIZE_FOR_SIZE
119-
if (source is Iterator<TSource> iterator)
119+
if (!IsSizeOptimized && source is Iterator<TSource> iterator)
120120
{
121121
int c = iterator.GetCount(onlyIfCheap: true);
122122
if (c >= 0)

src/libraries/System.Linq/src/System/Linq/ElementAt.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, int i
2424
bool found;
2525
TSource? element =
2626
#if !OPTIMIZE_FOR_SIZE
27-
source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
27+
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
2828
#endif
2929
TryGetElementAtNonIterator(source, index, out found);
3030

@@ -124,7 +124,7 @@ public static TSource ElementAt<TSource>(this IEnumerable<TSource> source, Index
124124

125125
return
126126
#if !OPTIMIZE_FOR_SIZE
127-
source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
127+
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetElementAt(index, out found) :
128128
#endif
129129
TryGetElementAtNonIterator(source, index, out found);
130130
}

src/libraries/System.Linq/src/System/Linq/Enumerable.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Collections.Generic;
5+
using System.Diagnostics.CodeAnalysis;
56
using System.Runtime.CompilerServices;
67
using System.Runtime.InteropServices;
78

89
namespace System.Linq
910
{
1011
public static partial class Enumerable
1112
{
13+
[FeatureSwitchDefinition("System.Linq.Enumerable.IsSizeOptimized")]
14+
internal static bool IsSizeOptimized { get; } = AppContext.TryGetSwitch("System.Linq.Enumerable.IsSizeOptimized", out bool isEnabled) ? isEnabled : false;
15+
1216
public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) => source;
1317

1418
/// <summary>Returns an empty <see cref="IEnumerable{TResult}"/>.</summary>

src/libraries/System.Linq/src/System/Linq/First.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source,
7171

7272
return
7373
#if !OPTIMIZE_FOR_SIZE
74-
source is Iterator<TSource> iterator ? iterator.TryGetFirst(out found) :
74+
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetFirst(out found) :
7575
#endif
7676
TryGetFirstNonIterator(source, out found);
7777
}

src/libraries/System.Linq/src/System/Linq/Iterator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public virtual IEnumerable<TResult> Select<TResult>(Func<TSource, TResult> selec
9191
#if OPTIMIZE_FOR_SIZE
9292
new IEnumerableSelectIterator<TSource, TResult>(this, selector);
9393
#else
94-
new IteratorSelectIterator<TSource, TResult>(this, selector);
94+
!IsSizeOptimized ? new IteratorSelectIterator<TSource, TResult>(this, selector) : new IEnumerableSelectIterator<TSource, TResult>(this, selector);
9595
#endif
9696

9797

src/libraries/System.Linq/src/System/Linq/Last.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public static TSource LastOrDefault<TSource>(this IEnumerable<TSource> source, F
7070

7171
return
7272
#if !OPTIMIZE_FOR_SIZE
73-
source is Iterator<TSource> iterator ? iterator.TryGetLast(out found) :
73+
!IsSizeOptimized && source is Iterator<TSource> iterator ? iterator.TryGetLast(out found) :
7474
#endif
7575
TryGetLastNonIterator(source, out found);
7676
}

src/libraries/System.Linq/src/System/Linq/Skip.SpeedOpt.cs

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,28 @@ namespace System.Linq
77
{
88
public static partial class Enumerable
99
{
10-
private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count) =>
11-
source is IList<TSource> sourceList ?
12-
(IEnumerable<TSource>)new IListSkipTakeIterator<TSource>(sourceList, count, int.MaxValue) :
13-
new IEnumerableSkipTakeIterator<TSource>(source, count, -1);
10+
private static IEnumerable<TSource> SkipIterator<TSource>(IEnumerable<TSource> source, int count)
11+
{
12+
if (IsSizeOptimized)
13+
{
14+
return SizeOptimizedSkipIterator(source, count);
15+
}
16+
else
17+
{
18+
return source is IList<TSource> sourceList ?
19+
(IEnumerable<TSource>)new IListSkipTakeIterator<TSource>(sourceList, count, int.MaxValue) :
20+
new IEnumerableSkipTakeIterator<TSource>(source, count, -1);
21+
}
22+
}
23+
24+
private static IEnumerable<TSource> SizeOptimizedSkipIterator<TSource>(IEnumerable<TSource> source, int count)
25+
{
26+
using IEnumerator<TSource> e = source.GetEnumerator();
27+
while (count > 0 && e.MoveNext()) count--;
28+
if (count <= 0)
29+
{
30+
while (e.MoveNext()) yield return e.Current;
31+
}
32+
}
1433
}
1534
}

src/libraries/System.Linq/src/System/Linq/Skip.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public static IEnumerable<TSource> Skip<TSource>(this IEnumerable<TSource> sourc
3131
count = 0;
3232
}
3333
#if !OPTIMIZE_FOR_SIZE
34-
else if (source is Iterator<TSource> iterator)
34+
else if (!IsSizeOptimized && source is Iterator<TSource> iterator)
3535
{
3636
return iterator.Skip(count) ?? Empty<TSource>();
3737
}

src/libraries/System.Linq/src/System/Linq/Take.SpeedOpt.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ private static IEnumerable<TSource> TakeIterator<TSource>(IEnumerable<TSource> s
1313
Debug.Assert(source is not null && !IsEmptyArray(source));
1414
Debug.Assert(count > 0);
1515

16+
if (IsSizeOptimized)
17+
return SizeOptimizedTakeIterator(source, count);
18+
1619
return
1720
source is Iterator<TSource> iterator ? (iterator.Take(count) ?? Empty<TSource>()) :
1821
source is IList<TSource> sourceList ? new IListSkipTakeIterator<TSource>(sourceList, 0, count - 1) :
@@ -24,6 +27,9 @@ private static IEnumerable<TSource> TakeRangeIterator<TSource>(IEnumerable<TSour
2427
Debug.Assert(source is not null && !IsEmptyArray(source));
2528
Debug.Assert(startIndex >= 0 && startIndex < endIndex);
2629

30+
if (IsSizeOptimized)
31+
return SizeOptimizedTakeRangeIterator(source, startIndex, endIndex);
32+
2733
return
2834
source is Iterator<TSource> iterator ? TakeIteratorRange(iterator, startIndex, endIndex) :
2935
source is IList<TSource> sourceList ? new IListSkipTakeIterator<TSource>(sourceList, startIndex, endIndex - 1) :
@@ -42,5 +48,41 @@ static IEnumerable<TSource> TakeIteratorRange(Iterator<TSource> iterator, int st
4248
return [];
4349
}
4450
}
51+
52+
private static IEnumerable<TSource> SizeOptimizedTakeIterator<TSource>(IEnumerable<TSource> source, int count)
53+
{
54+
Debug.Assert(count > 0);
55+
56+
foreach (TSource element in source)
57+
{
58+
yield return element;
59+
if (--count == 0) break;
60+
}
61+
}
62+
63+
private static IEnumerable<TSource> SizeOptimizedTakeRangeIterator<TSource>(IEnumerable<TSource> source, int startIndex, int endIndex)
64+
{
65+
Debug.Assert(source is not null);
66+
Debug.Assert(startIndex >= 0 && startIndex < endIndex);
67+
68+
using IEnumerator<TSource> e = source.GetEnumerator();
69+
70+
int index = 0;
71+
while (index < startIndex && e.MoveNext())
72+
{
73+
++index;
74+
}
75+
76+
if (index < startIndex)
77+
{
78+
yield break;
79+
}
80+
81+
while (index < endIndex && e.MoveNext())
82+
{
83+
yield return e.Current;
84+
++index;
85+
}
86+
}
4587
}
4688
}

0 commit comments

Comments
 (0)