• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2008 Google Inc.  All rights reserved.
4 //
5 // Use of this source code is governed by a BSD-style
6 // license that can be found in the LICENSE file or at
7 // https://developers.google.com/open-source/licenses/bsd
8 #endregion
9 
10 using System;
11 using System.Security;
12 
13 namespace Google.Protobuf
14 {
15     /// <summary>
16     /// Fast parsing primitives for wrapper types
17     /// </summary>
18     [SecuritySafeCritical]
19     internal static class ParsingPrimitivesWrappers
20     {
ReadFloatWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)21         internal static float? ReadFloatWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
22         {
23             // length:1 + tag:1 + value:4 = 6 bytes
24             if (state.bufferPos + 6 <= state.bufferSize)
25             {
26                 // The entire wrapper message is already contained in `buffer`.
27                 int length = buffer[state.bufferPos];
28                 if (length == 0)
29                 {
30                     state.bufferPos++;
31                     return 0F;
32                 }
33                 // tag:1 + value:4 = length of 5 bytes
34                 // field=1, type=32-bit = tag of 13
35                 if (length != 5 || buffer[state.bufferPos + 1] != 13)
36                 {
37                     return ReadFloatWrapperSlow(ref buffer, ref state);
38                 }
39                 state.bufferPos += 2;
40                 return ParsingPrimitives.ParseFloat(ref buffer, ref state);
41             }
42             else
43             {
44                 return ReadFloatWrapperSlow(ref buffer, ref state);
45             }
46         }
47 
ReadFloatWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)48         internal static float? ReadFloatWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
49         {
50             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
51             if (length == 0)
52             {
53                 return 0F;
54             }
55             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
56             float result = 0F;
57             do
58             {
59                 // field=1, type=32-bit = tag of 13
60                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 13)
61                 {
62                     result = ParsingPrimitives.ParseFloat(ref buffer, ref state);
63                 }
64                 else
65                 {
66                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
67                 }
68             }
69             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
70             return result;
71         }
72 
ReadDoubleWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)73         internal static double? ReadDoubleWrapperLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
74         {
75             // length:1 + tag:1 + value:8 = 10 bytes
76             if (state.bufferPos + 10 <= state.bufferSize)
77             {
78                 // The entire wrapper message is already contained in `buffer`.
79                 int length = buffer[state.bufferPos];
80                 if (length == 0)
81                 {
82                     state.bufferPos++;
83                     return 0D;
84                 }
85                 // tag:1 + value:8 = length of 9 bytes
86                 // field=1, type=64-bit = tag of 9
87                 if (length != 9 || buffer[state.bufferPos + 1] != 9)
88                 {
89                     return ReadDoubleWrapperSlow(ref buffer, ref state);
90                 }
91                 state.bufferPos += 2;
92                 return ParsingPrimitives.ParseDouble(ref buffer, ref state);
93             }
94             else
95             {
96                 return ReadDoubleWrapperSlow(ref buffer, ref state);
97             }
98         }
99 
ReadDoubleWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)100         internal static double? ReadDoubleWrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
101         {
102             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
103             if (length == 0)
104             {
105                 return 0D;
106             }
107             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
108             double result = 0D;
109             do
110             {
111                 // field=1, type=64-bit = tag of 9
112                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 9)
113                 {
114                     result = ParsingPrimitives.ParseDouble(ref buffer, ref state);
115                 }
116                 else
117                 {
118                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
119                 }
120             }
121             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
122             return result;
123         }
124 
ReadBoolWrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)125         internal static bool? ReadBoolWrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
126         {
127             return ReadUInt64Wrapper(ref buffer, ref state) != 0;
128         }
129 
ReadUInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)130         internal static uint? ReadUInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
131         {
132             // field=1, type=varint = tag of 8
133             const int expectedTag = 8;
134             // length:1 + tag:1 + value:10(varint64-max) = 12 bytes
135             // Value can be 64 bits for negative integers
136             if (state.bufferPos + 12 <= state.bufferSize)
137             {
138                 // The entire wrapper message is already contained in `buffer`.
139                 int pos0 = state.bufferPos;
140                 int length = buffer[state.bufferPos++];
141                 if (length == 0)
142                 {
143                     return 0;
144                 }
145                 // Length will always fit in a single byte.
146                 if (length >= 128)
147                 {
148                     state.bufferPos = pos0;
149                     return ReadUInt32WrapperSlow(ref buffer, ref state);
150                 }
151                 int finalBufferPos = state.bufferPos + length;
152                 if (buffer[state.bufferPos++] != expectedTag)
153                 {
154                     state.bufferPos = pos0;
155                     return ReadUInt32WrapperSlow(ref buffer, ref state);
156                 }
157                 var result = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
158                 // Verify this message only contained a single field.
159                 if (state.bufferPos != finalBufferPos)
160                 {
161                     state.bufferPos = pos0;
162                     return ReadUInt32WrapperSlow(ref buffer, ref state);
163                 }
164                 return result;
165             }
166             else
167             {
168                 return ReadUInt32WrapperSlow(ref buffer, ref state);
169             }
170         }
171 
ReadUInt32WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)172         internal static uint? ReadUInt32WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
173         {
174             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
175             if (length == 0)
176             {
177                 return 0;
178             }
179             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
180             uint result = 0;
181             do
182             {
183                 // field=1, type=varint = tag of 8
184                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == 8)
185                 {
186                     result = ParsingPrimitives.ParseRawVarint32(ref buffer, ref state);
187                 }
188                 else
189                 {
190                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
191                 }
192             }
193             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
194             return result;
195         }
196 
ReadInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)197         internal static int? ReadInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
198         {
199             return (int?)ReadUInt32Wrapper(ref buffer, ref state);
200         }
201 
ReadUInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)202         internal static ulong? ReadUInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
203         {
204             // field=1, type=varint = tag of 8
205             const int expectedTag = 8;
206             // length:1 + tag:1 + value:10(varint64-max) = 12 bytes
207             if (state.bufferPos + 12 <= state.bufferSize)
208             {
209                 // The entire wrapper message is already contained in `buffer`.
210                 int pos0 = state.bufferPos;
211                 int length = buffer[state.bufferPos++];
212                 if (length == 0)
213                 {
214                     return 0L;
215                 }
216                 // Length will always fit in a single byte.
217                 if (length >= 128)
218                 {
219                     state.bufferPos = pos0;
220                     return ReadUInt64WrapperSlow(ref buffer, ref state);
221                 }
222                 int finalBufferPos = state.bufferPos + length;
223                 if (buffer[state.bufferPos++] != expectedTag)
224                 {
225                     state.bufferPos = pos0;
226                     return ReadUInt64WrapperSlow(ref buffer, ref state);
227                 }
228                 var result = ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
229                 // Verify this message only contained a single field.
230                 if (state.bufferPos != finalBufferPos)
231                 {
232                     state.bufferPos = pos0;
233                     return ReadUInt64WrapperSlow(ref buffer, ref state);
234                 }
235                 return result;
236             }
237             else
238             {
239                 return ReadUInt64WrapperSlow(ref buffer, ref state);
240             }
241         }
242 
ReadUInt64WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)243         internal static ulong? ReadUInt64WrapperSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
244         {
245             // field=1, type=varint = tag of 8
246             const int expectedTag = 8;
247             int length = ParsingPrimitives.ParseLength(ref buffer, ref state);
248             if (length == 0)
249             {
250                 return 0L;
251             }
252             int finalBufferPos = state.totalBytesRetired + state.bufferPos + length;
253             ulong result = 0L;
254             do
255             {
256                 if (ParsingPrimitives.ParseTag(ref buffer, ref state) == expectedTag)
257                 {
258                     result = ParsingPrimitives.ParseRawVarint64(ref buffer, ref state);
259                 }
260                 else
261                 {
262                     ParsingPrimitivesMessages.SkipLastField(ref buffer, ref state);
263                 }
264             }
265             while (state.totalBytesRetired + state.bufferPos < finalBufferPos);
266             return result;
267         }
268 
ReadInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)269         internal static long? ReadInt64Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
270         {
271             return (long?)ReadUInt64Wrapper(ref buffer, ref state);
272         }
273 
ReadFloatWrapperLittleEndian(ref ParseContext ctx)274         internal static float? ReadFloatWrapperLittleEndian(ref ParseContext ctx)
275         {
276             return ParsingPrimitivesWrappers.ReadFloatWrapperLittleEndian(ref ctx.buffer, ref ctx.state);
277         }
278 
ReadFloatWrapperSlow(ref ParseContext ctx)279         internal static float? ReadFloatWrapperSlow(ref ParseContext ctx)
280         {
281             return ParsingPrimitivesWrappers.ReadFloatWrapperSlow(ref ctx.buffer, ref ctx.state);
282         }
283 
ReadDoubleWrapperLittleEndian(ref ParseContext ctx)284         internal static double? ReadDoubleWrapperLittleEndian(ref ParseContext ctx)
285         {
286             return ParsingPrimitivesWrappers.ReadDoubleWrapperLittleEndian(ref ctx.buffer, ref ctx.state);
287         }
288 
ReadDoubleWrapperSlow(ref ParseContext ctx)289         internal static double? ReadDoubleWrapperSlow(ref ParseContext ctx)
290         {
291             return ParsingPrimitivesWrappers.ReadDoubleWrapperSlow(ref ctx.buffer, ref ctx.state);
292         }
293 
ReadBoolWrapper(ref ParseContext ctx)294         internal static bool? ReadBoolWrapper(ref ParseContext ctx)
295         {
296             return ParsingPrimitivesWrappers.ReadBoolWrapper(ref ctx.buffer, ref ctx.state);
297         }
298 
ReadUInt32Wrapper(ref ParseContext ctx)299         internal static uint? ReadUInt32Wrapper(ref ParseContext ctx)
300         {
301             return ParsingPrimitivesWrappers.ReadUInt32Wrapper(ref ctx.buffer, ref ctx.state);
302         }
303 
ReadInt32Wrapper(ref ParseContext ctx)304         internal static int? ReadInt32Wrapper(ref ParseContext ctx)
305         {
306             return ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx.buffer, ref ctx.state);
307         }
308 
ReadUInt64Wrapper(ref ParseContext ctx)309         internal static ulong? ReadUInt64Wrapper(ref ParseContext ctx)
310         {
311             return ParsingPrimitivesWrappers.ReadUInt64Wrapper(ref ctx.buffer, ref ctx.state);
312         }
313 
ReadUInt64WrapperSlow(ref ParseContext ctx)314         internal static ulong? ReadUInt64WrapperSlow(ref ParseContext ctx)
315         {
316             return ParsingPrimitivesWrappers.ReadUInt64WrapperSlow(ref ctx.buffer, ref ctx.state);
317         }
318 
ReadInt64Wrapper(ref ParseContext ctx)319         internal static long? ReadInt64Wrapper(ref ParseContext ctx)
320         {
321             return ParsingPrimitivesWrappers.ReadInt64Wrapper(ref ctx.buffer, ref ctx.state);
322         }
323     }
324 }