Don't allocate in NullStream.CopyToAsync (#4383)
authorJames Ko <jamesqko@gmail.com>
Fri, 22 Apr 2016 00:14:21 +0000 (20:14 -0400)
committerJan Kotas <jkotas@microsoft.com>
Fri, 22 Apr 2016 00:14:21 +0000 (17:14 -0700)
src/mscorlib/model.xml
src/mscorlib/src/System/IO/Stream.cs

index c56b543..85727ce 100644 (file)
       <Member Name="get_Position" />
       <Member Name="get_ReadTimeout" />
       <Member Name="get_WriteTimeout" />
-      <Member Status="ImplRoot" Name="InternalCopyTo(System.IO.Stream,System.Int32)" />
       <Member Name="Read(System.Byte[],System.Int32,System.Int32)" />
       <Member Name="ReadByte" />
       <Member Name="ReadAsync(System.Byte[],System.Int32,System.Int32)"  />
index 999a2ad..aadbf7a 100644 (file)
@@ -137,19 +137,7 @@ namespace System.IO {
         [ComVisible(false)]
         public virtual Task CopyToAsync(Stream destination, Int32 bufferSize, CancellationToken cancellationToken)
         {
-            if (destination == null)
-                throw new ArgumentNullException("destination");
-            if (bufferSize <= 0)
-                throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
-            if (!CanRead && !CanWrite)
-                throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!destination.CanRead && !destination.CanWrite)
-                throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!CanRead)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
-            if (!destination.CanWrite)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
-            Contract.EndContractBlock();
+            ValidateCopyToArguments(destination, bufferSize);
 
             return CopyToAsyncInternal(destination, bufferSize, cancellationToken);
         }
@@ -174,47 +162,12 @@ namespace System.IO {
         // the current position.
         public void CopyTo(Stream destination)
         {
-            if (destination == null)
-                throw new ArgumentNullException("destination");
-            if (!CanRead && !CanWrite)
-                throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!destination.CanRead && !destination.CanWrite)
-                throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!CanRead)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
-            if (!destination.CanWrite)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
-            Contract.EndContractBlock();
-
-            InternalCopyTo(destination, _DefaultCopyBufferSize);
+            CopyTo(destination, _DefaultCopyBufferSize);
         }
 
         public void CopyTo(Stream destination, int bufferSize)
         {
-            if (destination == null)
-                throw new ArgumentNullException("destination");
-            if (bufferSize <= 0)
-                throw new ArgumentOutOfRangeException("bufferSize",
-                        Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
-            if (!CanRead && !CanWrite)
-                throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!destination.CanRead && !destination.CanWrite)
-                throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
-            if (!CanRead)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
-            if (!destination.CanWrite)
-                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
-            Contract.EndContractBlock();
-
-            InternalCopyTo(destination, bufferSize);
-        }
-
-        private void InternalCopyTo(Stream destination, int bufferSize)
-        {
-            Contract.Requires(destination != null);
-            Contract.Requires(CanRead);
-            Contract.Requires(destination.CanWrite);
-            Contract.Requires(bufferSize > 0);
+            ValidateCopyToArguments(destination, bufferSize);
             
             byte[] buffer = new byte[bufferSize];
             int read;
@@ -222,7 +175,6 @@ namespace System.IO {
                 destination.Write(buffer, 0, read);
         }
 
-
         // Stream used to require that all cleanup logic went into Close(),
         // which was thought up before we invented IDisposable.  However, we
         // need to follow the IDisposable pattern so that users can write 
@@ -871,6 +823,23 @@ namespace System.IO {
         {
             SynchronousAsyncResult.EndWrite(asyncResult);
         }
+        
+        internal void ValidateCopyToArguments(Stream destination, int bufferSize)
+        {
+            if (destination == null)
+                throw new ArgumentNullException("destination");
+            if (bufferSize <= 0)
+                throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
+            if (!CanRead && !CanWrite)
+                throw new ObjectDisposedException(null, Environment.GetResourceString("ObjectDisposed_StreamClosed"));
+            if (!destination.CanRead && !destination.CanWrite)
+                throw new ObjectDisposedException("destination", Environment.GetResourceString("ObjectDisposed_StreamClosed"));
+            if (!CanRead)
+                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnreadableStream"));
+            if (!destination.CanWrite)
+                throw new NotSupportedException(Environment.GetResourceString("NotSupported_UnwritableStream"));
+            Contract.EndContractBlock();
+        }
 
         [Serializable]
         private sealed class NullStream : Stream
@@ -900,6 +869,17 @@ namespace System.IO {
                 get { return 0; }
                 set {}
             }
+            
+            public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
+            {
+                // Validate arguments here for compat, since previously this method
+                // was inherited from Stream (which did check its arguments).
+                ValidateCopyToArguments(destination, bufferSize);
+                
+                return cancellationToken.IsCancellationRequested ?
+                    Task.FromCancellation(cancellationToken) :
+                    Task.CompletedTask;
+            }
 
             protected override void Dispose(bool disposing)
             {