Skip to content

Commit d9b8a09

Browse files
authored
Avoid pre-allocating large arrays in some scenarios for Enumerable.Chunk (#67210)
* Avoid pre-allocating large arrays in some scenarios for Enumerable.Chunk(). Fix #67132 * Switch Chunk() to use List-based implementation. See discussion here: #67210 (comment) * Address feedback from https://github.com/dotnet/runtime/pull/67210/files
1 parent c830e33 commit d9b8a09

File tree

2 files changed

+27
-18
lines changed

2 files changed

+27
-18
lines changed

src/libraries/System.Linq/src/System/Linq/Chunk.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
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

67
namespace System.Linq
78
{
@@ -50,26 +51,25 @@ public static IEnumerable<TSource[]> Chunk<TSource>(this IEnumerable<TSource> so
5051
private static IEnumerable<TSource[]> ChunkIterator<TSource>(IEnumerable<TSource> source, int size)
5152
{
5253
using IEnumerator<TSource> e = source.GetEnumerator();
53-
while (e.MoveNext())
54-
{
55-
TSource[] chunk = new TSource[size];
56-
chunk[0] = e.Current;
5754

58-
int i = 1;
59-
for (; i < chunk.Length && e.MoveNext(); i++)
55+
if (e.MoveNext())
56+
{
57+
List<TSource> chunkBuilder = new();
58+
while (true)
6059
{
61-
chunk[i] = e.Current;
62-
}
60+
do
61+
{
62+
chunkBuilder.Add(e.Current);
63+
}
64+
while (chunkBuilder.Count < size && e.MoveNext());
6365

64-
if (i == chunk.Length)
65-
{
66-
yield return chunk;
67-
}
68-
else
69-
{
70-
Array.Resize(ref chunk, i);
71-
yield return chunk;
72-
yield break;
66+
yield return chunkBuilder.ToArray();
67+
68+
if (chunkBuilder.Count < size || !e.MoveNext())
69+
{
70+
yield break;
71+
}
72+
chunkBuilder.Clear();
7373
}
7474
}
7575
}

src/libraries/System.Linq/tests/ChunkTests.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,5 +141,14 @@ public void AddingToSourceBeforeIterating()
141141

142142
Assert.Equal(new[] {new[] {9999, 0, 888}, new[] {-1, 66, -777}, new[] {1, 2, -12345}, new[] {10}}, chunks);
143143
}
144+
145+
// reproduces https://github.com/dotnet/runtime/issues/67132
146+
[Fact]
147+
public void DoesNotPrematurelyAllocateHugeArray()
148+
{
149+
int[][] chunks = Enumerable.Range(0, 10).Chunk(int.MaxValue).ToArray();
150+
151+
Assert.Equal(new[] { Enumerable.Range(0, 10).ToArray() }, chunks);
152+
}
144153
}
145-
}
154+
}

0 commit comments

Comments
 (0)