faster initialization of ParserInternalState

pull/7351/head
Jan Tattermusch 5 years ago
parent 42eff9d640
commit d17b5115d2
  1. 2
      csharp/src/Google.Protobuf/CodedInputStream.cs
  2. 2
      csharp/src/Google.Protobuf/ParseContext.cs
  3. 42
      csharp/src/Google.Protobuf/SegmentedBufferHelper.cs

@ -143,7 +143,7 @@ namespace Google.Protobuf
this.state.bufferSize = bufferSize;
this.state.sizeLimit = DefaultSizeLimit;
this.state.recursionLimit = DefaultRecursionLimit;
this.state.segmentedBufferHelper = new SegmentedBufferHelper(this);
SegmentedBufferHelper.Initialize(this, out this.state.segmentedBufferHelper);
this.state.codedInputStream = this;
this.leaveOpen = leaveOpen;

@ -89,7 +89,7 @@ namespace Google.Protobuf
this.state.sizeLimit = DefaultSizeLimit;
this.state.recursionLimit = recursionLimit;
this.state.currentLimit = int.MaxValue;
this.state.segmentedBufferHelper = new SegmentedBufferHelper(input, out this.buffer);
SegmentedBufferHelper.Initialize(input, out this.state.segmentedBufferHelper, out this.buffer);
this.state.bufferPos = 0;
this.state.bufferSize = this.buffer.Length;
this.state.codedInputStream = null;

@ -43,18 +43,37 @@ namespace Google.Protobuf
/// </summary>
internal struct SegmentedBufferHelper
{
private readonly int? totalLength;
private int? totalLength;
private ReadOnlySequence<byte>.Enumerator readOnlySequenceEnumerator;
private readonly CodedInputStream codedInputStream;
private CodedInputStream codedInputStream;
public SegmentedBufferHelper(ReadOnlySequence<byte> sequence, out ReadOnlySpan<byte> firstSpan)
/// <summary>
/// Initialize an instance with a coded input stream.
/// This approach is faster than using a constructor because the instance to initialize is passed by reference
/// and we can write directly into it without copying.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Initialize(CodedInputStream codedInputStream, out SegmentedBufferHelper instance)
{
instance.totalLength = codedInputStream.InternalInputStream == null ? (int?)codedInputStream.InternalBuffer.Length : null;
instance.readOnlySequenceEnumerator = default;
instance.codedInputStream = codedInputStream;
}
/// <summary>
/// Initialize an instance with a read only sequence.
/// This approach is faster than using a constructor because the instance to initialize is passed by reference
/// and we can write directly into it without copying.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Initialize(ReadOnlySequence<byte> sequence, out SegmentedBufferHelper instance, out ReadOnlySpan<byte> firstSpan)
{
this.codedInputStream = null;
instance.codedInputStream = null;
if (sequence.IsSingleSegment)
{
firstSpan = sequence.First.Span;
this.totalLength = firstSpan.Length;
this.readOnlySequenceEnumerator = default;
instance.totalLength = firstSpan.Length;
instance.readOnlySequenceEnumerator = default;
}
else
{
@ -62,17 +81,10 @@ namespace Google.Protobuf
// very first read will result in slowpath (because the first thing to do is to
// refill to get the first buffer segment)
firstSpan = default;
this.totalLength = (int) sequence.Length;
this.readOnlySequenceEnumerator = sequence.GetEnumerator();
instance.totalLength = (int) sequence.Length;
instance.readOnlySequenceEnumerator = sequence.GetEnumerator();
}
}
public SegmentedBufferHelper(CodedInputStream codedInputStream)
{
this.totalLength = codedInputStream.InternalInputStream == null ? (int?)codedInputStream.InternalBuffer.Length : null;
this.readOnlySequenceEnumerator = default;
this.codedInputStream = codedInputStream;
}
public bool RefillBuffer(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, bool mustSucceed)
{

Loading…
Cancel
Save