| File: System\IO\CachedConsoleStream.cs | Web Access |
| Project: src\runtime\src\libraries\System.Console\src\System.Console.csproj (System.Console) |
// 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 unsafe void Write(ReadOnlySpan<byte> buffer) { int maxCharCount = _encoding.GetMaxCharCount(buffer.Length); char[]? pooledBuffer = null; Span<char> charSpan = (uint)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); } } }