소스 검색

faster initialization of ParserInternalState

Jan Tattermusch 5 년 전
부모
커밋
d17b5115d2
3개의 변경된 파일29개의 추가작업 그리고 17개의 파일을 삭제
  1. 1 1
      csharp/src/Google.Protobuf/CodedInputStream.cs
  2. 1 1
      csharp/src/Google.Protobuf/ParseContext.cs
  3. 27 15
      csharp/src/Google.Protobuf/SegmentedBufferHelper.cs

+ 1 - 1
csharp/src/Google.Protobuf/CodedInputStream.cs

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

+ 1 - 1
csharp/src/Google.Protobuf/ParseContext.cs

@@ -89,7 +89,7 @@ namespace Google.Protobuf
             this.state.sizeLimit = DefaultSizeLimit;
             this.state.sizeLimit = DefaultSizeLimit;
             this.state.recursionLimit = recursionLimit;
             this.state.recursionLimit = recursionLimit;
             this.state.currentLimit = int.MaxValue;
             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.bufferPos = 0;
             this.state.bufferSize = this.buffer.Length;
             this.state.bufferSize = this.buffer.Length;
             this.state.codedInputStream = null;
             this.state.codedInputStream = null;

+ 27 - 15
csharp/src/Google.Protobuf/SegmentedBufferHelper.cs

@@ -43,18 +43,37 @@ namespace Google.Protobuf
     /// </summary>
     /// </summary>
     internal struct SegmentedBufferHelper
     internal struct SegmentedBufferHelper
     {
     {
-        private readonly int? totalLength;
+        private int? totalLength;
         private ReadOnlySequence<byte>.Enumerator readOnlySequenceEnumerator;
         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)
             if (sequence.IsSingleSegment)
             {
             {
                 firstSpan = sequence.First.Span;
                 firstSpan = sequence.First.Span;
-                this.totalLength = firstSpan.Length;
-                this.readOnlySequenceEnumerator = default;
+                instance.totalLength = firstSpan.Length;
+                instance.readOnlySequenceEnumerator = default;
             }
             }
             else
             else
             {
             {
@@ -62,17 +81,10 @@ namespace Google.Protobuf
                 // very first read will result in slowpath (because the first thing to do is to
                 // very first read will result in slowpath (because the first thing to do is to
                 // refill to get the first buffer segment)
                 // refill to get the first buffer segment)
                 firstSpan = default;
                 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)
         public bool RefillBuffer(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, bool mustSucceed)
         {
         {