Skip to content

Commit

Permalink
Implemented TextReader.ReadLineAsync(CancellationToken) and TextReade…
Browse files Browse the repository at this point in the history
…r.ReadToEndAsync(CancellationToken)
  • Loading branch information
orthoxerox committed May 13, 2021
1 parent b7f54e9 commit 22ed6ed
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 15 deletions.
24 changes: 14 additions & 10 deletions src/libraries/System.Private.CoreLib/src/System/IO/StreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -813,8 +813,10 @@ private int ReadBuffer(Span<char> userBuffer, out bool readToUserBuffer)
} while (ReadBuffer() > 0);
return sb.ToString();
}

public override Task<string?> ReadLineAsync() => ReadLineAsync(CancellationToken.None);

public override Task<string?> ReadLineAsync()
public override Task<string?> ReadLineAsync(CancellationToken cancellationToken)
{
// If we have been inherited into a subclass, the following implementation could be incorrect
// since it does not call through to Read() which a subclass might have overridden.
Expand All @@ -828,15 +830,15 @@ private int ReadBuffer(Span<char> userBuffer, out bool readToUserBuffer)
ThrowIfDisposed();
CheckAsyncTaskInProgress();

Task<string?> task = ReadLineAsyncInternal();
Task<string?> task = ReadLineAsyncInternal(cancellationToken);
_asyncReadTask = task;

return task;
}

private async Task<string?> ReadLineAsyncInternal()
private async Task<string?> ReadLineAsyncInternal(CancellationToken cancellationToken)
{
if (_charPos == _charLen && (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false)) == 0)
if (_charPos == _charLen && (await ReadBufferAsync(cancellationToken).ConfigureAwait(false)) == 0)
{
return null;
}
Expand Down Expand Up @@ -872,7 +874,7 @@ private int ReadBuffer(Span<char> userBuffer, out bool readToUserBuffer)

_charPos = tmpCharPos = i + 1;

if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false)) > 0))
if (ch == '\r' && (tmpCharPos < tmpCharLen || (await ReadBufferAsync(cancellationToken).ConfigureAwait(false)) > 0))
{
tmpCharPos = _charPos;
if (_charBuffer[tmpCharPos] == '\n')
Expand All @@ -890,12 +892,14 @@ private int ReadBuffer(Span<char> userBuffer, out bool readToUserBuffer)
i = tmpCharLen - tmpCharPos;
sb ??= new StringBuilder(i + 80);
sb.Append(tmpCharBuffer, tmpCharPos, i);
} while (await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false) > 0);
} while (await ReadBufferAsync(cancellationToken).ConfigureAwait(false) > 0);

return sb.ToString();
}

public override Task<string> ReadToEndAsync()
public override Task<string> ReadToEndAsync() => ReadToEndAsync(CancellationToken.None);

public override Task<string> ReadToEndAsync(CancellationToken cancellationToken)
{
// If we have been inherited into a subclass, the following implementation could be incorrect
// since it does not call through to Read() which a subclass might have overridden.
Expand All @@ -909,13 +913,13 @@ public override Task<string> ReadToEndAsync()
ThrowIfDisposed();
CheckAsyncTaskInProgress();

Task<string> task = ReadToEndAsyncInternal();
Task<string> task = ReadToEndAsyncInternal(cancellationToken);
_asyncReadTask = task;

return task;
}

private async Task<string> ReadToEndAsyncInternal()
private async Task<string> ReadToEndAsyncInternal(CancellationToken cancellationToken)
{
// Call ReadBuffer, then pull data out of charBuffer.
StringBuilder sb = new StringBuilder(_charLen - _charPos);
Expand All @@ -924,7 +928,7 @@ private async Task<string> ReadToEndAsyncInternal()
int tmpCharPos = _charPos;
sb.Append(_charBuffer, tmpCharPos, _charLen - tmpCharPos);
_charPos = _charLen; // We consumed these characters
await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false);
await ReadBufferAsync(cancellationToken).ConfigureAwait(false);
} while (_charLen > 0);

return sb.ToString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,12 +210,16 @@ public override string ReadToEnd()
}

#region Task based Async APIs
public override Task<string?> ReadLineAsync()
public override Task<string?> ReadLineAsync() => ReadLineAsync(CancellationToken.None);

public override Task<string?> ReadLineAsync(CancellationToken cancellationToken)
{
return Task.FromResult(ReadLine());
}

public override Task<string> ReadToEndAsync()
public override Task<string> ReadToEndAsync() => ReadToEndAsync(CancellationToken.None);

public override Task<string> ReadToEndAsync(CancellationToken cancellationToken)
{
return Task.FromResult(ReadToEnd());
}
Expand Down
10 changes: 7 additions & 3 deletions src/libraries/System.Private.CoreLib/src/System/IO/TextReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,18 +203,22 @@ public virtual int ReadBlock(Span<char> buffer)
}

#region Task based Async APIs
public virtual Task<string?> ReadLineAsync() =>
public virtual Task<string?> ReadLineAsync() => ReadLineAsync(CancellationToken.None);

public virtual async Task<string?> ReadLineAsync(CancellationToken cancellationToken) =>
Task<string?>.Factory.StartNew(static state => ((TextReader)state!).ReadLine(), this,
CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);

public virtual async Task<string> ReadToEndAsync()
public virtual async Task<string> ReadToEndAsync() => ReadToEndAsync(CancellationToken.None);

public virtual async Task<string> ReadToEndAsync(CancellationToken cancellationToken)
{
var sb = new StringBuilder(4096);
char[] chars = ArrayPool<char>.Shared.Rent(4096);
try
{
int len;
while ((len = await ReadAsyncInternal(chars, default).ConfigureAwait(false)) != 0)
while ((len = await ReadAsyncInternal(chars, cancellationToken).ConfigureAwait(false)) != 0)
{
sb.Append(chars, 0, len);
}
Expand Down

0 comments on commit 22ed6ed

Please sign in to comment.