Use GC.AllocateUninitializedArray in MemoryStream.ToArray (#50692)
authorBruce Bowyer-Smyth <bbowyersmyth@live.com.au>
Mon, 5 Apr 2021 02:19:41 +0000 (12:19 +1000)
committerGitHub <noreply@github.com>
Mon, 5 Apr 2021 02:19:41 +0000 (22:19 -0400)
* Use GC.AllocateUninitializedArray in MemoryStream.ToArray

* Apply suggestions from code review

Co-authored-by: Stephen Toub <stoub@microsoft.com>
Co-authored-by: Stephen Toub <stoub@microsoft.com>
src/libraries/System.IO/tests/MemoryStream/MemoryStream.ToArrayTests.cs [new file with mode: 0644]
src/libraries/System.IO/tests/System.IO.Tests.csproj
src/libraries/System.Private.CoreLib/src/System/IO/MemoryStream.cs

diff --git a/src/libraries/System.IO/tests/MemoryStream/MemoryStream.ToArrayTests.cs b/src/libraries/System.IO/tests/MemoryStream/MemoryStream.ToArrayTests.cs
new file mode 100644 (file)
index 0000000..1f787de
--- /dev/null
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Security.Cryptography;
+
+namespace System.IO.Tests
+{
+    public class MemoryStream_ToArrayTests
+    {
+        [Theory]
+        [MemberData(nameof(GetArraysVariedBySize))]
+        public static void ToArray_ZeroOffset(byte[] array)
+        {
+            var stream = new MemoryStream();
+            stream.Write(array);
+            var newArray = stream.ToArray();
+
+            Assert.Equal(array.Length, newArray.Length);
+            Assert.Equal(array, newArray);
+        }
+
+        [Theory]
+        [MemberData(nameof(GetArraysVariedBySize))]
+        public static void ToArray_Offset(byte[] array)
+        {
+            int index = 0;
+            int count = array.Length;
+
+            if (count > 3)
+            {
+                // Trim some off each end
+                index = 1;
+                count -= 3;
+            }
+
+            var stream = new MemoryStream(array, index, count);
+            var newArray = stream.ToArray();
+
+            Assert.Equal(count, newArray.Length);
+            Assert.True(array.AsSpan(index, count).SequenceEqual(newArray));
+        }
+
+        public static IEnumerable<object[]> GetArraysVariedBySize()
+        {
+            yield return new object[] { RandomNumberGenerator.GetBytes(0) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(1) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(2) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(256) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(512) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(1024) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(2047) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(2048) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(2049) };
+            yield return new object[] { RandomNumberGenerator.GetBytes(2100) };
+        }
+    }
+}
index 3bf8d26..b0a0339 100644 (file)
@@ -9,6 +9,7 @@
   <ItemGroup>
     <Compile Include="IndentedTextWriter.cs" />
     <Compile Include="BinaryReader\BinaryReaderTests.cs" />
+    <Compile Include="MemoryStream\MemoryStream.ToArrayTests.cs" />
     <Compile Include="MemoryStream\MemoryStream.GetBufferTests.cs" />
     <Compile Include="StreamReader\StreamReader.cs" />
     <Compile Include="StreamReader\StreamReader.StringCtorTests.cs" />
index d9b30c0..8175eb9 100644 (file)
@@ -602,8 +602,8 @@ namespace System.IO
             int count = _length - _origin;
             if (count == 0)
                 return Array.Empty<byte>();
-            byte[] copy = new byte[count];
-            Buffer.BlockCopy(_buffer, _origin, copy, 0, count);
+            byte[] copy = GC.AllocateUninitializedArray<byte>(count);
+            _buffer.AsSpan(_origin, count).CopyTo(copy);
             return copy;
         }