-
Notifications
You must be signed in to change notification settings - Fork 62
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Benjamin Hodgson
committed
Jul 24, 2020
1 parent
4141044
commit 851dc1c
Showing
9 changed files
with
120 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using System; | ||
using System.IO; | ||
using Pidgin.TokenStreams; | ||
using Xunit; | ||
|
||
namespace Pidgin.Tests | ||
{ | ||
public class ReusableTokenStreamTests | ||
{ | ||
[Fact] | ||
public void TestResume() | ||
{ | ||
var input = "aaabb"; | ||
var stream = new ResumableTokenStream<char>(new ReaderTokenStream(new StringReader(input))); | ||
|
||
// consume two 'a's, reject the third one | ||
var chunk = new char[3].AsSpan(); | ||
stream.Read(chunk); | ||
stream.OnParserEnd(chunk.Slice(2)); | ||
|
||
stream.Read(chunk); | ||
Assert.Equal("abb", chunk.ToString()); | ||
} | ||
|
||
[Fact] | ||
public void TestReturnMultipleChunks() | ||
{ | ||
var stream = new ResumableTokenStream<char>(new ReaderTokenStream(new StringReader(""))); | ||
stream.OnParserEnd("aa"); | ||
stream.OnParserEnd("bb"); | ||
|
||
var chunk = new char[4].AsSpan(); | ||
stream.Read(chunk); | ||
Assert.Equal("bbaa", chunk.ToString()); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Runtime.CompilerServices; | ||
|
||
namespace Pidgin.TokenStreams | ||
{ | ||
internal class ResumableTokenStream<TToken> : ITokenStream<TToken>, IDisposable | ||
{ | ||
private static readonly bool _needsClear = RuntimeHelpers.IsReferenceOrContainsReferences<TToken>(); | ||
private readonly ArrayPool<TToken> _pool; | ||
private readonly ITokenStream<TToken> _next; | ||
private TToken[]? _buffer = null; | ||
private int _bufferStart = 0; // amount of empty space at left-hand end of _buffer, aka index of first value | ||
|
||
public ResumableTokenStream(ITokenStream<TToken> next, ArrayPool<TToken>? pool = null) | ||
{ | ||
if (next == null) | ||
{ | ||
throw new ArgumentNullException(nameof(next)); | ||
} | ||
_next = next; | ||
_pool = pool ?? ArrayPool<TToken>.Shared; | ||
} | ||
|
||
public int Read(Span<TToken> buffer) | ||
{ | ||
var bufferedCount = 0; | ||
if (_buffer != null && _bufferStart < _buffer.Length) | ||
{ | ||
bufferedCount = Math.Min(_buffer.Length - _bufferStart, buffer.Length); | ||
_buffer.AsSpan().Slice(_bufferStart, bufferedCount).CopyTo(buffer); | ||
_bufferStart += bufferedCount; | ||
} | ||
return bufferedCount + _next.Read(buffer.Slice(bufferedCount)); | ||
} | ||
|
||
public void OnParserEnd(ReadOnlySpan<TToken> unconsumed) | ||
{ | ||
if (unconsumed.Length == 0) | ||
{ | ||
return; | ||
} | ||
if (_buffer == null) | ||
{ | ||
_buffer = _pool.Rent(unconsumed.Length); | ||
_bufferStart = _buffer.Length; | ||
} | ||
if (_bufferStart < unconsumed.Length) | ||
{ | ||
var bufferedCount = _buffer.Length - _bufferStart; | ||
var newBuffer = _pool.Rent(bufferedCount + unconsumed.Length); | ||
var newBufferStart = newBuffer.Length - bufferedCount; | ||
|
||
Array.Copy(_buffer, _bufferStart, newBuffer, newBufferStart, bufferedCount); | ||
|
||
_pool.Return(_buffer, _needsClear); | ||
_buffer = newBuffer; | ||
_bufferStart = newBufferStart; | ||
} | ||
_bufferStart -= unconsumed.Length; | ||
unconsumed.CopyTo(_buffer.AsSpan().Slice(_bufferStart)); | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
if (_buffer != null) | ||
{ | ||
_pool.Return(_buffer, _needsClear); | ||
_bufferStart = 0; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters