<Compile Include="System\ConsoleKeyInfo.cs" />
<Compile Include="System\ConsoleModifiers.cs" />
<Compile Include="System\IO\ConsoleStream.cs" />
+ <Compile Include="System\IO\CachedConsoleStream.cs" />
<Compile Include="System\IO\SyncTextReader.cs" />
<Compile Include="System\IO\Error.cs" />
<Compile Include="$(CommonPath)System\Text\ConsoleEncoding.cs"
namespace System
{
- internal sealed unsafe class LogcatStream : ConsoleStream
+ internal sealed unsafe class LogcatStream : CachedConsoleStream
{
- public LogcatStream() : base(FileAccess.Write) {}
+ public LogcatStream(Encoding encoding) : base(encoding) {}
- public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();
-
- public override unsafe void Write(ReadOnlySpan<byte> buffer)
+ protected override void Print(ReadOnlySpan<char> line)
{
- string log = ConsolePal.OutputEncoding.GetString(buffer);
+ string log = line.ToString();
Interop.Logcat.AndroidLogPrint(Interop.Logcat.LogLevel.Info, "DOTNET", log);
}
}
public static Stream OpenStandardInput() => throw new PlatformNotSupportedException();
- public static Stream OpenStandardOutput() => new LogcatStream();
+ public static Stream OpenStandardOutput() => new LogcatStream(OutputEncoding);
- public static Stream OpenStandardError() => new LogcatStream();
+ public static Stream OpenStandardError() => new LogcatStream(OutputEncoding);
public static Encoding InputEncoding => throw new PlatformNotSupportedException();
namespace System
{
- internal sealed class NSLogStream : ConsoleStream
+ internal sealed class NSLogStream : CachedConsoleStream
{
- private readonly StringBuilder _buffer = new StringBuilder();
- private readonly Encoding _encoding;
- private readonly Decoder _decoder;
+ public NSLogStream(Encoding encoding) : base(encoding) {}
- public NSLogStream(Encoding encoding) : base(FileAccess.Write)
+ protected override unsafe void Print(ReadOnlySpan<char> line)
{
- _encoding = encoding;
- _decoder = _encoding.GetDecoder();
- }
-
- public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();
-
- public override void Write(ReadOnlySpan<byte> buffer)
- {
- int maxCharCount = _encoding.GetMaxCharCount(buffer.Length);
- char[]? pooledBuffer = null;
- Span<char> charSpan = maxCharCount <= 512 ? stackalloc char[512] : (pooledBuffer = ArrayPool<char>.Shared.Rent(maxCharCount));
- try
- {
- int count = _decoder.GetChars(buffer, charSpan, false);
- if (count > 0)
- {
- WriteOrCache(_buffer, charSpan.Slice(0, count));
- }
- }
- finally
- {
- if (pooledBuffer != null)
- {
- ArrayPool<char>.Shared.Return(pooledBuffer);
- }
- }
- }
-
- private static void WriteOrCache(StringBuilder cache, Span<char> charBuffer)
- {
- int lastNewLine = charBuffer.LastIndexOf('\n');
- if (lastNewLine != -1)
- {
- Span<char> lineSpan = charBuffer.Slice(0, lastNewLine);
- if (cache.Length > 0)
- {
- Print(cache.Append(lineSpan).ToString());
- cache.Clear();
- }
- else
- {
- Print(lineSpan);
- }
-
- if (lastNewLine + 1 < charBuffer.Length)
- {
- cache.Append(charBuffer.Slice(lastNewLine + 1));
- }
-
- return;
- }
-
- // no newlines found, add the entire buffer to the cache
- cache.Append(charBuffer);
-
- static unsafe void Print(ReadOnlySpan<char> line)
+ fixed (char* ptr = line)
{
- fixed (char* ptr = line)
- {
- Interop.Sys.Log((byte*)ptr, line.Length * 2);
- }
+ Interop.Sys.Log((byte*)ptr, line.Length * 2);
}
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Buffers;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace System.IO
+{
+ internal abstract class CachedConsoleStream : ConsoleStream
+ {
+ private readonly StringBuilder _buffer = new StringBuilder();
+ private readonly Encoding _encoding;
+ private readonly Decoder _decoder;
+
+ public CachedConsoleStream(Encoding encoding) : base(FileAccess.Write)
+ {
+ _encoding = encoding;
+ _decoder = _encoding.GetDecoder();
+ }
+
+ public override int Read(Span<byte> buffer) => throw Error.GetReadNotSupported();
+
+ public override void Write(ReadOnlySpan<byte> buffer)
+ {
+ int maxCharCount = _encoding.GetMaxCharCount(buffer.Length);
+ char[]? pooledBuffer = null;
+ Span<char> charSpan = maxCharCount <= 512 ? stackalloc char[512] : (pooledBuffer = ArrayPool<char>.Shared.Rent(maxCharCount));
+ try
+ {
+ int count = _decoder.GetChars(buffer, charSpan, false);
+ if (count > 0)
+ {
+ WriteOrCache(this, _buffer, charSpan.Slice(0, count));
+ }
+ }
+ finally
+ {
+ if (pooledBuffer != null)
+ {
+ ArrayPool<char>.Shared.Return(pooledBuffer);
+ }
+ }
+ }
+
+ protected abstract void Print(ReadOnlySpan<char> line);
+
+ private static void WriteOrCache(CachedConsoleStream stream, StringBuilder cache, Span<char> charBuffer)
+ {
+ int lastNewLine = charBuffer.LastIndexOf('\n');
+ if (lastNewLine != -1)
+ {
+ Span<char> lineSpan = charBuffer.Slice(0, lastNewLine);
+ if (cache.Length > 0)
+ {
+ stream.Print(cache.Append(lineSpan).ToString());
+ cache.Clear();
+ }
+ else
+ {
+ stream.Print(lineSpan);
+ }
+
+ if (lastNewLine + 1 < charBuffer.Length)
+ {
+ cache.Append(charBuffer.Slice(lastNewLine + 1));
+ }
+
+ return;
+ }
+
+ // no newlines found, add the entire buffer to the cache
+ cache.Append(charBuffer);
+ }
+ }
+}