Skip to content

Commit 337f96c

Browse files
Merge pull request #801 from stebet/serializationOptimizations
Serialization optimizations
2 parents 0f1761f + ea6dd27 commit 337f96c

File tree

2 files changed

+97
-26
lines changed

2 files changed

+97
-26
lines changed
Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,124 @@
11
using System;
2-
using System.Buffers.Binary;
32
using System.Runtime.CompilerServices;
43

54
namespace RabbitMQ.Util
65
{
76
internal static class NetworkOrderDeserializer
87
{
8+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
99
internal static double ReadDouble(ReadOnlyMemory<byte> memory) => ReadDouble(memory.Span);
1010

11+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1112
internal static double ReadDouble(ReadOnlySpan<byte> span)
1213
{
1314
if (span.Length < 8)
1415
{
1516
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode Double from memory.");
1617
}
1718

18-
long val = BinaryPrimitives.ReadInt64BigEndian(span);
19-
return Unsafe.As<long, double>(ref val);
19+
ulong val = ReadUInt64(span);
20+
return Unsafe.As<ulong, double>(ref val);
2021
}
2122

23+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2224
internal static short ReadInt16(ReadOnlyMemory<byte> memory) => ReadInt16(memory.Span);
2325

26+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2427
internal static short ReadInt16(ReadOnlySpan<byte> span)
2528
{
2629
if (span.Length < 2)
2730
{
2831
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode Int16 from memory.");
2932
}
3033

31-
return BinaryPrimitives.ReadInt16BigEndian(span);
34+
return (short)ReadUInt16(span);
3235
}
3336

37+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3438
internal static int ReadInt32(ReadOnlyMemory<byte> memory) => ReadInt32(memory.Span);
3539

40+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3641
internal static int ReadInt32(ReadOnlySpan<byte> span)
3742
{
3843
if (span.Length < 4)
3944
{
4045
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode Int32 from memory.");
4146
}
4247

43-
return BinaryPrimitives.ReadInt32BigEndian(span);
48+
return (int)ReadUInt32(span);
4449
}
4550

51+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4652
internal static long ReadInt64(ReadOnlyMemory<byte> memory) => ReadInt64(memory.Span);
4753

54+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4855
internal static long ReadInt64(ReadOnlySpan<byte> span)
4956
{
5057
if (span.Length < 8)
5158
{
5259
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode Int64 from memory.");
5360
}
5461

55-
return BinaryPrimitives.ReadInt64BigEndian(span);
62+
return (long)ReadUInt64(span);
5663
}
5764

65+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5866
internal static float ReadSingle(ReadOnlyMemory<byte> memory) => ReadSingle(memory.Span);
5967

68+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6069
internal static float ReadSingle(ReadOnlySpan<byte> span)
6170
{
6271
if (span.Length < 4)
6372
{
6473
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode Single from memory.");
6574
}
6675

67-
int num = BinaryPrimitives.ReadInt32BigEndian(span);
68-
return Unsafe.As<int, float>(ref num);
76+
uint num = ReadUInt32(span);
77+
return Unsafe.As<uint, float>(ref num);
6978
}
7079

80+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7181
internal static ushort ReadUInt16(ReadOnlyMemory<byte> memory) => ReadUInt16(memory.Span);
7282

83+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7384
internal static ushort ReadUInt16(ReadOnlySpan<byte> span)
7485
{
7586
if (span.Length < 2)
7687
{
7788
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode UInt16 from memory.");
7889
}
7990

80-
return BinaryPrimitives.ReadUInt16BigEndian(span);
91+
return (ushort)((span[0] << 8) | span[1]);
8192
}
8293

94+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8395
internal static uint ReadUInt32(ReadOnlyMemory<byte> memory) => ReadUInt32(memory.Span);
8496

97+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8598
internal static uint ReadUInt32(ReadOnlySpan<byte> span)
8699
{
87100
if (span.Length < 4)
88101
{
89102
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode UInt32 from memory.");
90103
}
91104

92-
return BinaryPrimitives.ReadUInt32BigEndian(span);
105+
return (uint)((span[0] << 24) | (span[1] << 16) | (span[2] << 8) | span[3]);
93106
}
94107

108+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
95109
internal static ulong ReadUInt64(ReadOnlyMemory<byte> memory) => ReadUInt64(memory.Span);
96110

111+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
97112
internal static ulong ReadUInt64(ReadOnlySpan<byte> span)
98113
{
99114
if (span.Length < 8)
100115
{
101116
throw new ArgumentOutOfRangeException(nameof(span), "Insufficient length to decode UInt64 from memory.");
102117
}
103118

104-
return BinaryPrimitives.ReadUInt64BigEndian(span);
119+
uint num1 = (uint)((span[0] << 24) | (span[1] << 16) | (span[2] << 8) | span[3]);
120+
uint num2 = (uint)((span[4] << 24) | (span[5] << 16) | (span[6] << 8) | span[7]);
121+
return ((ulong)num1 << 32) | num2;
105122
}
106123
}
107124
}
Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,94 +1,148 @@
11
using System;
22
using System.Buffers.Binary;
3+
using System.Runtime.CompilerServices;
4+
using System.Runtime.InteropServices;
35

46
namespace RabbitMQ.Util
57
{
68
internal static class NetworkOrderSerializer
79
{
10+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
811
internal static void WriteDouble(Memory<byte> memory, double val)
912
{
1013
if (memory.Length < 8)
1114
{
1215
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Double to memory.");
1316
}
1417

15-
BinaryPrimitives.WriteInt64BigEndian(memory.Span, BitConverter.DoubleToInt64Bits(val));
18+
long tempVal = BitConverter.DoubleToInt64Bits(val);
19+
SerializeInt64(memory.Span, tempVal);
1620
}
1721

22+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
1823
internal static void WriteInt16(Memory<byte> memory, short val)
1924
{
2025
if (memory.Length < 2)
2126
{
2227
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Int16 to memory.");
2328
}
2429

25-
BinaryPrimitives.WriteInt16BigEndian(memory.Span, val);
30+
SerializeInt16(memory.Span, val);
2631
}
2732

33+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2834
internal static void WriteInt32(Memory<byte> memory, int val)
2935
{
3036
if (memory.Length < 4)
3137
{
3238
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Int32 to memory.");
3339
}
3440

35-
BinaryPrimitives.WriteInt32BigEndian(memory.Span, val);
41+
SerializeInt32(memory.Span, val);
3642
}
3743

44+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
3845
internal static void WriteInt64(Memory<byte> memory, long val)
3946
{
4047
if (memory.Length < 8)
4148
{
4249
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Int64 to memory.");
4350
}
4451

45-
BinaryPrimitives.WriteInt64BigEndian(memory.Span, val);
46-
}
52+
SerializeInt64(memory.Span, val);
53+
}
4754

55+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4856
internal static void WriteSingle(Memory<byte> memory, float val)
4957
{
5058
if (memory.Length < 4)
5159
{
5260
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Single to memory.");
5361
}
5462

55-
byte[] bytes = BitConverter.GetBytes(val);
56-
if (BitConverter.IsLittleEndian)
57-
{
58-
Array.Reverse(bytes);
59-
}
60-
61-
bytes.AsMemory().CopyTo(memory);
63+
int tempVal = Unsafe.As<float, int>(ref val);
64+
SerializeInt32(memory.Span, tempVal);
6265
}
6366

67+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6468
internal static void WriteUInt16(Memory<byte> memory, ushort val)
6569
{
6670
if (memory.Length < 2)
6771
{
6872
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write UInt16 to memory.");
6973
}
7074

71-
BinaryPrimitives.WriteUInt16BigEndian(memory.Span, val);
75+
SerializeUInt16(memory.Span, val);
7276
}
7377

78+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
7479
internal static void WriteUInt32(Memory<byte> memory, uint val)
7580
{
7681
if (memory.Length < 4)
7782
{
7883
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write UInt32 to memory.");
7984
}
8085

81-
BinaryPrimitives.WriteUInt32BigEndian(memory.Span, val);
86+
SerializeUInt32(memory.Span, val);
8287
}
8388

89+
90+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8491
internal static void WriteUInt64(Memory<byte> memory, ulong val)
8592
{
8693
if (memory.Length < 8)
8794
{
8895
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write UInt64 from memory.");
8996
}
9097

91-
BinaryPrimitives.WriteUInt64BigEndian(memory.Span, val);
98+
SerializeUInt64(memory.Span, val);
99+
}
100+
101+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
102+
private static void SerializeInt16(Span<byte> memory, short val)
103+
{
104+
SerializeUInt16(memory, (ushort)val);
105+
}
106+
107+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
108+
private static void SerializeUInt16(Span<byte> memory, ushort val)
109+
{
110+
memory[0] = (byte)((val >> 8) & 0xFF);
111+
memory[1] = (byte)(val & 0xFF);
112+
}
113+
114+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
115+
private static void SerializeInt32(Span<byte> memory, int val)
116+
{
117+
SerializeUInt32(memory, (uint)val);
118+
}
119+
120+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
121+
private static void SerializeUInt32(Span<byte> memory, uint val)
122+
{
123+
memory[0] = (byte)((val >> 24) & 0xFF);
124+
memory[1] = (byte)((val >> 16) & 0xFF);
125+
memory[2] = (byte)((val >> 8) & 0xFF);
126+
memory[3] = (byte)(val & 0xFF);
127+
}
128+
129+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
130+
private static void SerializeInt64(Span<byte> memory, long val)
131+
{
132+
SerializeUInt64(memory, (ulong)val);
133+
}
134+
135+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
136+
private static void SerializeUInt64(Span<byte> memory, ulong val)
137+
{
138+
memory[0] = (byte)((val >> 56) & 0xFF);
139+
memory[1] = (byte)((val >> 48) & 0xFF);
140+
memory[2] = (byte)((val >> 40) & 0xFF);
141+
memory[3] = (byte)((val >> 32) & 0xFF);
142+
memory[4] = (byte)((val >> 24) & 0xFF);
143+
memory[5] = (byte)((val >> 16) & 0xFF);
144+
memory[6] = (byte)((val >> 8) & 0xFF);
145+
memory[7] = (byte)(val & 0xFF);
92146
}
93147
}
94148
}

0 commit comments

Comments
 (0)