faster initialization of ParserInternalState
diff --git a/csharp/src/Google.Protobuf/CodedInputStream.cs b/csharp/src/Google.Protobuf/CodedInputStream.cs
index 3235cca..4c9234d 100644
--- a/csharp/src/Google.Protobuf/CodedInputStream.cs
+++ b/csharp/src/Google.Protobuf/CodedInputStream.cs
@@ -143,7 +143,7 @@
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;
diff --git a/csharp/src/Google.Protobuf/ParseContext.cs b/csharp/src/Google.Protobuf/ParseContext.cs
index 4d0c140..6c74e73 100644
--- a/csharp/src/Google.Protobuf/ParseContext.cs
+++ b/csharp/src/Google.Protobuf/ParseContext.cs
@@ -89,7 +89,7 @@
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;
diff --git a/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs b/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
index 2c9db88..a8a7562 100644
--- a/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
+++ b/csharp/src/Google.Protobuf/SegmentedBufferHelper.cs
@@ -43,18 +43,37 @@
/// </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)
{
- this.codedInputStream = null;
+ 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)
+ {
+ 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 @@
// 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)
{