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] [Test]
public void TestReadToEndAfterReadsAndPeeks() 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 stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
using (var bufferedReader = new LineBufferedReader(stream)) using (var bufferedReader = new LineBufferedReader(stream))
{ {
Assert.AreEqual("this line is gone", bufferedReader.ReadLine()); bufferedReader.PeekLine();
Assert.AreEqual("this one shouldn't be", bufferedReader.PeekLine()); Assert.Throws<InvalidOperationException>(() => bufferedReader.ReadToEnd());
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]);
} }
} }
} }

View File

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

View File

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