Skip to content

Commit e5c3514

Browse files
committed
Add Code
1 parent 59a8de6 commit e5c3514

File tree

2 files changed

+51
-9
lines changed

2 files changed

+51
-9
lines changed

csharp/src/Google.Protobuf/Collections/RepeatedField.cs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88
#endregion
99

1010
using System;
11+
using System.Buffers;
1112
using System.Collections;
1213
using System.Collections.Generic;
1314
using System.Diagnostics;
1415
using System.IO;
1516
using System.Linq;
17+
using System.Runtime.InteropServices;
1618
using System.Security;
1719
#if NET5_0_OR_GREATER
1820
using System.Runtime.CompilerServices;
@@ -116,12 +118,31 @@ public void AddEntriesFrom(ref ParseContext ctx, FieldCodec<T> codec)
116118
{
117119
EnsureSize(count + (length / codec.FixedSize));
118120

119-
while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state))
121+
122+
// if little endian try to copy packed buffer into RepeatedField array
123+
if(BitConverter.IsLittleEndian)
124+
{
125+
unsafe
126+
{
127+
GCHandle gcHandle = GCHandle.Alloc(array, GCHandleType.Pinned);
128+
IntPtr addr = gcHandle.AddrOfPinnedObject();
129+
Span<byte> span = new Span<byte>(addr.ToPointer(), array.Length * codec.FixedSize)
130+
.Slice(count * codec.FixedSize);
131+
Debug.Assert(span.Length >= length);
132+
ParsingPrimitives.ReadPackedFieldLittleEndian(ref ctx.buffer, ref ctx.state, length, span);
133+
count += length / codec.FixedSize;
134+
gcHandle.Free();
135+
}
136+
}
137+
else
120138
{
121-
// Only FieldCodecs with a fixed size can reach here, and they are all known
122-
// types that don't allow the user to specify a custom reader action.
123-
// reader action will never return null.
124-
array[count++] = reader(ref ctx);
139+
while (!SegmentedBufferHelper.IsReachedLimit(ref ctx.state))
140+
{
141+
// Only FieldCodecs with a fixed size can reach here, and they are all known
142+
// types that don't allow the user to specify a custom reader action.
143+
// reader action will never return null.
144+
array[count++] = reader(ref ctx);
145+
}
125146
}
126147
}
127148
else

csharp/src/Google.Protobuf/ParsingPrimitives.cs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Buffers;
1212
using System.Buffers.Binary;
1313
using System.Collections.Generic;
14+
using System.Diagnostics;
1415
using System.IO;
1516
using System.Runtime.CompilerServices;
1617
using System.Runtime.InteropServices;
@@ -45,7 +46,7 @@ public static int ParseLength(ref ReadOnlySpan<byte> buffer, ref ParserInternalS
4546

4647
/// <summary>
4748
/// Parses the next tag.
48-
/// If the end of logical stream was reached, an invalid tag of 0 is returned.
49+
/// If the end of logical stream was reached, an invalid tag of 0 is returned.
4950
/// </summary>
5051
public static uint ParseTag(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
5152
{
@@ -382,7 +383,7 @@ public static float ParseFloat(ref ReadOnlySpan<byte> buffer, ref ParserInternal
382383
// ReadUnaligned uses processor architecture for endianness.
383384
float result = Unsafe.ReadUnaligned<float>(ref MemoryMarshal.GetReference(buffer.Slice(state.bufferPos, length)));
384385
state.bufferPos += length;
385-
return result;
386+
return result;
386387
}
387388

388389
private static unsafe float ParseFloatSlow(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
@@ -737,7 +738,7 @@ public static uint ReadRawVarint32(Stream input)
737738
/// </summary>
738739
/// <remarks>
739740
/// ZigZag encodes signed integers into values that can be efficiently
740-
/// encoded with varint. (Otherwise, negative values must be
741+
/// encoded with varint. (Otherwise, negative values must be
741742
/// sign-extended to 32 bits to be varint encoded, thus always taking
742743
/// 5 bytes on the wire.)
743744
/// </remarks>
@@ -751,7 +752,7 @@ public static int DecodeZigZag32(uint n)
751752
/// </summary>
752753
/// <remarks>
753754
/// ZigZag encodes signed integers into values that can be efficiently
754-
/// encoded with varint. (Otherwise, negative values must be
755+
/// encoded with varint. (Otherwise, negative values must be
755756
/// sign-extended to 64 bits to be varint encoded, thus always taking
756757
/// 10 bytes on the wire.)
757758
/// </remarks>
@@ -810,5 +811,25 @@ private static void ReadRawBytesIntoSpan(ref ReadOnlySpan<byte> buffer, ref Pars
810811
state.bufferPos += unreadSpan.Length;
811812
}
812813
}
814+
815+
/// <summary>
816+
/// Read LittleEndian packed field from buffer of specified length into a span.
817+
/// The amount of data available and the current limit should be checked before calling this method.
818+
/// </summary>
819+
internal static void ReadPackedFieldLittleEndian(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state, int length, Span<byte> outBuffer)
820+
{
821+
Debug.Assert(BitConverter.IsLittleEndian);
822+
823+
if (length <= state.bufferSize - state.bufferPos)
824+
{
825+
buffer.Slice(state.bufferPos, length).CopyTo(outBuffer);
826+
state.bufferPos += length;
827+
}
828+
else
829+
{
830+
ReadRawBytesIntoSpan(ref buffer, ref state, length, outBuffer);
831+
}
832+
}
833+
813834
}
814835
}

0 commit comments

Comments
 (0)