Use ArrayPool in Stream.CopyTo{Async}
authorStephen Toub <stoub@microsoft.com>
Mon, 31 Oct 2016 02:08:26 +0000 (22:08 -0400)
committerStephen Toub <stoub@microsoft.com>
Mon, 31 Oct 2016 02:10:58 +0000 (22:10 -0400)
src/mscorlib/src/System/IO/Stream.cs

index 738bb0c..745b970 100644 (file)
@@ -15,6 +15,9 @@
 **
 ===========================================================*/
 using System;
+#if FEATURE_CORECLR
+using System.Buffers;
+#endif
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -171,6 +174,25 @@ namespace System.IO {
             Contract.Requires(CanRead);
             Contract.Requires(destination.CanWrite);
 
+#if FEATURE_CORECLR
+            byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
+            bufferSize = 0; // reuse same field for high water mark to avoid needing another field in the state machine
+            try
+            {
+                while (true)
+                {
+                    int bytesRead = await ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false);
+                    if (bytesRead == 0) break;
+                    if (bytesRead > bufferSize) bufferSize = bytesRead;
+                    await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
+                }
+            }
+            finally
+            {
+                Array.Clear(buffer, 0, bufferSize); // clear only the most we used
+                ArrayPool<byte>.Shared.Return(buffer, clearArray: false);
+            }
+#else
             byte[] buffer = new byte[bufferSize];
             while (true)
             {
@@ -178,6 +200,7 @@ namespace System.IO {
                 if (bytesRead == 0) break;
                 await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
             }
+#endif
         }
 
         // Reads the bytes from the current stream and writes the bytes to
@@ -214,11 +237,32 @@ namespace System.IO {
         public virtual void CopyTo(Stream destination, int bufferSize)
         {
             StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
-            
+
+#if FEATURE_CORECLR
+            byte[] buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
+            int highwaterMark = 0;
+            try
+            {
+                int read;
+                while ((read = Read(buffer, 0, buffer.Length)) != 0)
+                {
+                    if (read > highwaterMark) highwaterMark = read;
+                    destination.Write(buffer, 0, read);
+                }
+            }
+            finally
+            {
+                Array.Clear(buffer, 0, highwaterMark); // clear only the most we used
+                ArrayPool<byte>.Shared.Return(buffer, clearArray: false);
+            }
+#else
             byte[] buffer = new byte[bufferSize];
             int read;
             while ((read = Read(buffer, 0, buffer.Length)) != 0)
+            {
                 destination.Write(buffer, 0, read);
+            }
+#endif
         }
 
         // Stream used to require that all cleanup logic went into Close(),