Enable NRT and simplify LineBufferedReader

This commit is contained in:
Dean Herbert
2022-07-06 14:29:55 +09:00
parent 73a5f9e911
commit a52ea3cabe
3 changed files with 23 additions and 39 deletions

View File

@ -108,19 +108,13 @@ namespace osu.Game.Tests.Beatmaps.IO
[Test]
public void TestReadToEndAfterReadsAndPeeks()
{
const string contents = "this line is gone\rthis one shouldn't be\r\nthese ones\ndefinitely not";
const string contents = "first line\r\nsecond line";
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
using (var bufferedReader = new LineBufferedReader(stream))
{
Assert.AreEqual("this line is gone", bufferedReader.ReadLine());
Assert.AreEqual("this one shouldn't be", bufferedReader.PeekLine());
string[] endingLines = bufferedReader.ReadToEnd().Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
Assert.AreEqual(3, endingLines.Length);
Assert.AreEqual("this one shouldn't be", endingLines[0]);
Assert.AreEqual("these ones", endingLines[1]);
Assert.AreEqual("definitely not", endingLines[2]);
bufferedReader.PeekLine();
Assert.Throws<InvalidOperationException>(() => bufferedReader.ReadToEnd());
}
}
}

View File

@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps.Formats
{
Section section = Section.General;
string line;
string? line;
while ((line = stream.ReadLine()) != null)
{

View File

@ -1,10 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
@ -17,58 +14,51 @@ namespace osu.Game.IO
public class LineBufferedReader : IDisposable
{
private readonly StreamReader streamReader;
private readonly Queue<string> lineBuffer;
private string? peekedLine;
public LineBufferedReader(Stream stream, bool leaveOpen = false)
{
streamReader = new StreamReader(stream, Encoding.UTF8, true, 1024, leaveOpen);
lineBuffer = new Queue<string>();
}
/// <summary>
/// Reads the next line from the stream without consuming it.
/// Subsequent calls to <see cref="PeekLine"/> without a <see cref="ReadLine"/> will return the same string.
/// </summary>
public string PeekLine()
{
if (lineBuffer.Count > 0)
return lineBuffer.Peek();
string line = streamReader.ReadLine();
if (line != null)
lineBuffer.Enqueue(line);
return line;
}
public string? PeekLine() => peekedLine ??= streamReader.ReadLine();
/// <summary>
/// Reads the next line from the stream and consumes it.
/// If a line was peeked, that same line will then be consumed and returned.
/// </summary>
public string ReadLine() => lineBuffer.Count > 0 ? lineBuffer.Dequeue() : streamReader.ReadLine();
public string? ReadLine()
{
try
{
return peekedLine ?? streamReader.ReadLine();
}
finally
{
peekedLine = null;
}
}
/// <summary>
/// Reads the stream to its end and returns the text read.
/// This includes any peeked but unconsumed lines.
/// Not compatible with calls to <see cref="PeekLine"/>.
/// </summary>
public string ReadToEnd()
{
string remainingText = streamReader.ReadToEnd();
if (lineBuffer.Count == 0)
return remainingText;
if (peekedLine != null)
throw new InvalidOperationException($"Do not use {nameof(ReadToEnd)} when also peeking for lines.");
var builder = new StringBuilder();
// this might not be completely correct due to varying platform line endings
while (lineBuffer.Count > 0)
builder.AppendLine(lineBuffer.Dequeue());
builder.Append(remainingText);
return builder.ToString();
return streamReader.ReadToEnd();
}
public void Dispose()
{
streamReader?.Dispose();
streamReader.Dispose();
}
}
}