Merge pull request #946 from akoeplinger/fix-mono-parallel
[mono.git] / mcs / class / corlib / System.IO / MemoryStream.cs
index 45673b328e641e96a0c61075b8b759639c168322..4ce86df30b616f0b9ff96498f8d7fa783d76a698 100644 (file)
@@ -4,14 +4,12 @@
 // Authors:    Marcin Szczepanski (marcins@zipworld.com.au)
 //             Patrik Torstensson
 //             Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//             Marek Safar (marek.safar@gmail.com)
 //
 // (c) 2001,2002 Marcin Szczepanski, Patrik Torstensson
 // (c) 2003 Ximian, Inc. (http://www.ximian.com)
-// Copyright (C) 2004 Novell (http://www.novell.com)
-//
-
-//
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 
 using System.Globalization;
 using System.Runtime.InteropServices;
+using System.Threading;
+#if NET_4_5
+using System.Threading.Tasks;
+#endif
 
 namespace System.IO
 {
@@ -53,6 +55,10 @@ namespace System.IO
                bool streamClosed;
                int position;
                int dirty_bytes;
+#if NET_4_5
+               [NonSerialized]
+               Task<int> read_task;
+#endif
 
                public MemoryStream () : this (0)
                {
@@ -153,8 +159,6 @@ namespace System.IO
 
                        set {
                                CheckIfClosedThrowDisposed ();
-                               if (value == capacity)
-                                       return; // LAMENESS: see MemoryStreamTest.ConstructorFive
 
                                if (!expandable)
                                        throw new NotSupportedException ("Cannot expand this MemoryStream");
@@ -163,13 +167,14 @@ namespace System.IO
                                        throw new ArgumentOutOfRangeException ("value",
                                        "New capacity cannot be negative or less than the current capacity " + value + " " + capacity);
 
-                               if (value == internalBuffer.Length)
+                               if (internalBuffer != null && value == internalBuffer.Length)
                                        return;
 
                                byte [] newBuffer = null;
                                if (value != 0) {
                                        newBuffer = new byte [value];
-                                       Buffer.BlockCopy (internalBuffer, 0, newBuffer, 0, length);
+                                       if (internalBuffer != null)
+                                               Buffer.BlockCopy (internalBuffer, 0, newBuffer, 0, length);
                                }
 
                                dirty_bytes = 0; // discard any dirty area beyond previous length
@@ -233,8 +238,6 @@ namespace System.IO
 
                public override int Read ([In,Out] byte [] buffer, int offset, int count)
                {
-                       CheckIfClosedThrowDisposed ();
-
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
 
@@ -245,6 +248,8 @@ namespace System.IO
                                throw new ArgumentException ("offset+count",
                                                              "The size of the buffer is less than offset + count.");
 
+                       CheckIfClosedThrowDisposed ();
+
                        if (position >= length || count == 0)
                                return 0;
 
@@ -371,11 +376,6 @@ namespace System.IO
 
                public override void Write (byte [] buffer, int offset, int count)
                {
-                       CheckIfClosedThrowDisposed ();
-
-                       if (!canWrite)
-                               throw new NotSupportedException ("Cannot write to this stream.");
-
                        if (buffer == null)
                                throw new ArgumentNullException ("buffer");
                        
@@ -386,6 +386,11 @@ namespace System.IO
                                throw new ArgumentException ("offset+count",
                                                             "The size of the buffer is less than offset + count.");
 
+                       CheckIfClosedThrowDisposed ();
+
+                       if (!CanWrite)
+                               throw new NotSupportedException ("Cannot write to this stream.");
+
                        // reordered to avoid possible integer overflow
                        if (position > length - count)
                                Expand (position + count);
@@ -420,9 +425,75 @@ namespace System.IO
                        stream.Write (internalBuffer, initialIndex, length - initialIndex);
                }
 
-#if NET_4_0
-               protected override void ObjectInvariant ()
+#if NET_4_5
+
+               public override Task CopyToAsync (Stream destination, int bufferSize, CancellationToken cancellationToken)
+               {
+                       // TODO: Specialization but what for?
+                       return base.CopyToAsync (destination, bufferSize, cancellationToken);
+               }
+
+               public override Task FlushAsync (CancellationToken cancellationToken)
+               {
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants.Canceled;
+
+                       try {
+                               Flush ();
+                               return TaskConstants.Finished;
+                       } catch (Exception ex) {
+                               return Task<object>.FromException (ex);
+                       }
+               }
+
+               public override Task<int> ReadAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
                {
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+
+                       if (offset < 0 || count < 0)
+                               throw new ArgumentOutOfRangeException ("offset or count less than zero.");
+
+                       if (buffer.Length - offset < count )
+                               throw new ArgumentException ("offset+count",
+                                                            "The size of the buffer is less than offset + count.");
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants<int>.Canceled;
+
+                       try {
+                               count = Read (buffer, offset, count);
+
+                               // Try not to allocate a new task for every buffer read
+                               if (read_task == null || read_task.Result != count)
+                                       read_task = Task<int>.FromResult (count);
+
+                               return read_task;
+                       } catch (Exception ex) {
+                               return Task<int>.FromException (ex);
+                       }
+               }
+
+               public override Task WriteAsync (byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+               {
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+                       
+                       if (offset < 0 || count < 0)
+                               throw new ArgumentOutOfRangeException ();
+
+                       if (buffer.Length - offset < count)
+                               throw new ArgumentException ("offset+count",
+                                                            "The size of the buffer is less than offset + count.");
+
+                       if (cancellationToken.IsCancellationRequested)
+                               return TaskConstants.Canceled;
+
+                       try {
+                               Write (buffer, offset, count);
+                               return TaskConstants.Finished;
+                       } catch (Exception ex) {
+                               return Task<object>.FromException (ex);
+                       }
                }
 #endif
        }