Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs')
-rw-r--r--src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs187
1 files changed, 157 insertions, 30 deletions
diff --git a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
index a37624428..8d94ac60b 100644
--- a/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
+++ b/src/System.Private.CoreLib/shared/System/IO/StreamWriter.cs
@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
@@ -44,19 +45,21 @@ namespace System.IO
// We don't guarantee thread safety on StreamWriter, but we should at
// least prevent users from trying to write anything while an Async
// write from the same thread is in progress.
- private volatile Task _asyncWriteTask;
+ private Task _asyncWriteTask = Task.CompletedTask;
private void CheckAsyncTaskInProgress()
{
// We are not locking the access to _asyncWriteTask because this is not meant to guarantee thread safety.
// We are simply trying to deter calling any Write APIs while an async Write from the same thread is in progress.
-
- Task t = _asyncWriteTask;
-
- if (t != null && !t.IsCompleted)
- throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+ if (!_asyncWriteTask.IsCompleted)
+ {
+ ThrowAsyncIOInProgress();
+ }
}
+ private static void ThrowAsyncIOInProgress() =>
+ throw new InvalidOperationException(SR.InvalidOperation_AsyncIOInProgress);
+
// The high level goal is to be tolerant of encoding errors when we read and very strict
// when we write. Hence, default StreamWriter encoding will throw on encoding error.
// Note: when StreamWriter throws on invalid encoding chars (for ex, high surrogate character
@@ -323,14 +326,13 @@ namespace System.IO
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(char[] buffer)
{
- if (buffer != null)
- {
- WriteCore(buffer, _autoFlush);
- }
+ WriteSpan(buffer, appendNewLine: false);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(char[] buffer, int index, int count)
{
if (buffer == null)
@@ -350,14 +352,15 @@ namespace System.IO
throw new ArgumentException(SR.Argument_InvalidOffLen);
}
- WriteCore(new ReadOnlySpan<char>(buffer, index, count), _autoFlush);
+ WriteSpan(buffer.AsSpan(index, count), appendNewLine: false);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(ReadOnlySpan<char> buffer)
{
if (GetType() == typeof(StreamWriter))
{
- WriteCore(buffer, _autoFlush);
+ WriteSpan(buffer, appendNewLine: false);
}
else
{
@@ -367,7 +370,8 @@ namespace System.IO
}
}
- private unsafe void WriteCore(ReadOnlySpan<char> buffer, bool autoFlush)
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void WriteSpan(ReadOnlySpan<char> buffer, bool appendNewLine)
{
CheckAsyncTaskInProgress();
@@ -422,41 +426,47 @@ namespace System.IO
}
}
- if (autoFlush)
+ if (appendNewLine)
+ {
+ char[] coreNewLine = CoreNewLine;
+ for (int i = 0; i < coreNewLine.Length; i++) // Generally 1 (\n) or 2 (\r\n) iterations
+ {
+ if (_charPos == _charLen)
+ {
+ Flush(false, false);
+ }
+
+ _charBuffer[_charPos] = coreNewLine[i];
+ _charPos++;
+ }
+ }
+
+ if (_autoFlush)
{
Flush(true, false);
}
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void Write(string value)
{
- if (value != null)
- {
- WriteCore(value.AsSpan(), _autoFlush);
- }
+ WriteSpan(value, appendNewLine: false);
}
- //
- // Optimize the most commonly used WriteLine overload. This optimization is important for System.Console in particular
- // because of it will make one WriteLine equal to one call to the OS instead of two in the common case.
- //
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void WriteLine(string value)
{
CheckAsyncTaskInProgress();
- if (value != null)
- {
- WriteCore(value.AsSpan(), autoFlush: false);
- }
- WriteCore(new ReadOnlySpan<char>(CoreNewLine), autoFlush: true);
+ WriteSpan(value, appendNewLine: true);
}
+ [MethodImpl(MethodImplOptions.NoInlining)] // prevent WriteSpan from bloating call sites
public override void WriteLine(ReadOnlySpan<char> value)
{
if (GetType() == typeof(StreamWriter))
{
CheckAsyncTaskInProgress();
- WriteCore(value, autoFlush: false);
- WriteCore(new ReadOnlySpan<char>(CoreNewLine), autoFlush: true);
+ WriteSpan(value, appendNewLine: true);
}
else
{
@@ -466,6 +476,123 @@ namespace System.IO
}
}
+ private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine)
+ {
+ StringBuilder sb =
+ StringBuilderCache.Acquire(format.Length + args.Length * 8)
+ .AppendFormatHelper(null, format, args);
+
+ StringBuilder.ChunkEnumerator chunks = sb.GetChunks();
+
+ bool more = chunks.MoveNext();
+ while (more)
+ {
+ ReadOnlySpan<char> current = chunks.Current.Span;
+ more = chunks.MoveNext();
+
+ // If final chunk, include the newline if needed
+ WriteSpan(current, appendNewLine: more ? false : appendNewLine);
+ }
+
+ StringBuilderCache.Release(sb);
+ }
+
+ public override void Write(string format, object arg0)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0);
+ }
+ }
+
+ public override void Write(string format, object arg0, object arg1)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0, arg1);
+ }
+ }
+
+ public override void Write(string format, object arg0, object arg1, object arg2)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg0, arg1, arg2);
+ }
+ }
+
+ public override void Write(string format, params object[] arg)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: false);
+ }
+ else
+ {
+ base.Write(format, arg);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0, object arg1)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0, arg1);
+ }
+ }
+
+ public override void WriteLine(string format, object arg0, object arg1, object arg2)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg0, arg1, arg2);
+ }
+ }
+
+ public override void WriteLine(string format, params object[] arg)
+ {
+ if (GetType() == typeof(StreamWriter))
+ {
+ WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: true);
+ }
+ else
+ {
+ base.WriteLine(format, arg);
+ }
+ }
+
#region Task based Async APIs
public override Task WriteAsync(char value)
{
@@ -955,7 +1082,7 @@ namespace System.IO
// to ensure performant access inside the state machine that corresponds this async method.
private static async Task FlushAsyncInternal(StreamWriter _this, bool flushStream, bool flushEncoder,
char[] charBuffer, int charPos, bool haveWrittenPreamble,
- Encoding encoding, Encoder encoder, Byte[] byteBuffer, Stream stream, CancellationToken cancellationToken)
+ Encoding encoding, Encoder encoder, byte[] byteBuffer, Stream stream, CancellationToken cancellationToken)
{
if (!haveWrittenPreamble)
{