diff --git a/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs b/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
index fd17c34b1053..b91a202922bd 100644
--- a/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
+++ b/src/Common/src/System/Collections/Generic/LargeArrayBuilder.cs
@@ -42,6 +42,20 @@ internal CopyPosition(int row, int column)
///
internal int Column { get; }
+ ///
+ /// If this position is at the end of the current buffer, returns the position
+ /// at the start of the next buffer. Otherwise, returns this position.
+ ///
+ /// The length of the current buffer.
+ public CopyPosition Normalize(int endColumn)
+ {
+ Debug.Assert(Column <= endColumn);
+
+ return Column == endColumn ?
+ new CopyPosition(Row + 1, 0) :
+ this;
+ }
+
///
/// Gets a string suitable for display in the debugger.
///
@@ -197,9 +211,10 @@ public void CopyTo(T[] array, int arrayIndex, int count)
/// The position in this builder that was copied up to.
public CopyPosition CopyTo(CopyPosition position, T[] array, int arrayIndex, int count)
{
+ Debug.Assert(array != null);
Debug.Assert(arrayIndex >= 0);
- Debug.Assert(count >= 0 && count <= Count);
- Debug.Assert(array?.Length - arrayIndex >= count);
+ Debug.Assert(count > 0 && count <= Count);
+ Debug.Assert(array.Length - arrayIndex >= count);
// Go through each buffer, which contains one 'row' of items.
// The index in each buffer is referred to as the 'column'.
@@ -216,25 +231,35 @@ public CopyPosition CopyTo(CopyPosition position, T[] array, int arrayIndex, int
int row = position.Row;
int column = position.Column;
- for (; count > 0; row++, column = 0)
+ T[] buffer = GetBuffer(row);
+ int copied = CopyToCore(buffer, column);
+
+ if (count == 0)
{
- T[] buffer = GetBuffer(index: row);
+ return new CopyPosition(row, column + copied).Normalize(buffer.Length);
+ }
- // During this iteration, copy until we satisfy `count` or reach the
- // end of the current buffer.
- int copyCount = Math.Min(buffer.Length, count);
+ do
+ {
+ buffer = GetBuffer(++row);
+ copied = CopyToCore(buffer, 0);
+ } while (count > 0);
- if (copyCount > 0)
- {
- Array.Copy(buffer, column, array, arrayIndex, copyCount);
+ return new CopyPosition(row, copied).Normalize(buffer.Length);
- arrayIndex += copyCount;
- count -= copyCount;
- column += copyCount;
- }
- }
+ int CopyToCore(T[] sourceBuffer, int sourceIndex)
+ {
+ Debug.Assert(sourceBuffer.Length > sourceIndex);
+
+ // Copy until we satisfy `count` or reach the end of the current buffer.
+ int copyCount = Math.Min(sourceBuffer.Length - sourceIndex, count);
+ Array.Copy(sourceBuffer, sourceIndex, array, arrayIndex, copyCount);
- return new CopyPosition(row: row, column: column);
+ arrayIndex += copyCount;
+ count -= copyCount;
+
+ return copyCount;
+ }
}
///
diff --git a/src/Common/src/System/Collections/Generic/SparseArrayBuilder.cs b/src/Common/src/System/Collections/Generic/SparseArrayBuilder.cs
index 57eeeb90b6e5..4829a9ce464c 100644
--- a/src/Common/src/System/Collections/Generic/SparseArrayBuilder.cs
+++ b/src/Common/src/System/Collections/Generic/SparseArrayBuilder.cs
@@ -113,9 +113,10 @@ public SparseArrayBuilder(bool initialize)
/// The number of items to copy.
public void CopyTo(T[] array, int arrayIndex, int count)
{
+ Debug.Assert(array != null);
Debug.Assert(arrayIndex >= 0);
Debug.Assert(count >= 0 && count <= Count);
- Debug.Assert(array?.Length - arrayIndex >= count);
+ Debug.Assert(array.Length - arrayIndex >= count);
int copied = 0;
var position = CopyPosition.Start;
@@ -149,8 +150,11 @@ public void CopyTo(T[] array, int arrayIndex, int count)
count -= reservedCount;
}
- // Finish copying after the final marker.
- _builder.CopyTo(position, array, arrayIndex, count);
+ if (count > 0)
+ {
+ // Finish copying after the final marker.
+ _builder.CopyTo(position, array, arrayIndex, count);
+ }
}
///
diff --git a/src/System.Linq/tests/ConcatTests.cs b/src/System.Linq/tests/ConcatTests.cs
index 89b9052942bc..425fefbdd736 100644
--- a/src/System.Linq/tests/ConcatTests.cs
+++ b/src/System.Linq/tests/ConcatTests.cs
@@ -421,5 +421,123 @@ public void GetEnumerableOfConcatCollectionChainFollowedByEnumerableNodeShouldBe
Assert.Equal(0xf00, en.Current);
}
}
+
+ [Theory]
+ [MemberData(nameof(GetToArrayDataSources))]
+ public void CollectionInterleavedWithLazyEnumerables_ToArray(IEnumerable[] arrays)
+ {
+ // See https://github.com/dotnet/corefx/issues/23680
+
+ IEnumerable concats = arrays[0];
+
+ for (int i = 1; i < arrays.Length; i++)
+ {
+ concats = concats.Concat(arrays[i]);
+ }
+
+ int[] results = concats.ToArray();
+
+ for (int i = 0; i < results.Length; i++)
+ {
+ Assert.Equal(i, results[i]);
+ }
+ }
+
+ private static IEnumerable