Skip to content

Serialization optimizations #801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions projects/RabbitMQ.Client/util/NetworkOrderDeserializer.cs
Original file line number Diff line number Diff line change
@@ -1,107 +1,124 @@
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;

namespace RabbitMQ.Util
{
internal static class NetworkOrderDeserializer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static double ReadDouble(ReadOnlyMemory<byte> memory) => ReadDouble(memory.Span);

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

long val = BinaryPrimitives.ReadInt64BigEndian(span);
return Unsafe.As<long, double>(ref val);
ulong val = ReadUInt64(span);
return Unsafe.As<ulong, double>(ref val);
}

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

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

return BinaryPrimitives.ReadInt16BigEndian(span);
return (short)ReadUInt16(span);
}

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

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

return BinaryPrimitives.ReadInt32BigEndian(span);
return (int)ReadUInt32(span);
}

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

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

return BinaryPrimitives.ReadInt64BigEndian(span);
return (long)ReadUInt64(span);
}

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

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

int num = BinaryPrimitives.ReadInt32BigEndian(span);
return Unsafe.As<int, float>(ref num);
uint num = ReadUInt32(span);
return Unsafe.As<uint, float>(ref num);
}

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

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

return BinaryPrimitives.ReadUInt16BigEndian(span);
return (ushort)((span[0] << 8) | span[1]);
}

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

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

return BinaryPrimitives.ReadUInt32BigEndian(span);
return (uint)((span[0] << 24) | (span[1] << 16) | (span[2] << 8) | span[3]);
}

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

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

return BinaryPrimitives.ReadUInt64BigEndian(span);
uint num1 = (uint)((span[0] << 24) | (span[1] << 16) | (span[2] << 8) | span[3]);
uint num2 = (uint)((span[4] << 24) | (span[5] << 16) | (span[6] << 8) | span[7]);
return ((ulong)num1 << 32) | num2;
}
}
}
84 changes: 69 additions & 15 deletions projects/RabbitMQ.Client/util/NetworkOrderSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,94 +1,148 @@
using System;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace RabbitMQ.Util
{
internal static class NetworkOrderSerializer
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void WriteDouble(Memory<byte> memory, double val)
{
if (memory.Length < 8)
{
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write Double to memory.");
}

BinaryPrimitives.WriteInt64BigEndian(memory.Span, BitConverter.DoubleToInt64Bits(val));
long tempVal = BitConverter.DoubleToInt64Bits(val);
SerializeInt64(memory.Span, tempVal);
}

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

BinaryPrimitives.WriteInt16BigEndian(memory.Span, val);
SerializeInt16(memory.Span, val);
}

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

BinaryPrimitives.WriteInt32BigEndian(memory.Span, val);
SerializeInt32(memory.Span, val);
}

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

BinaryPrimitives.WriteInt64BigEndian(memory.Span, val);
}
SerializeInt64(memory.Span, val);
}

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

byte[] bytes = BitConverter.GetBytes(val);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(bytes);
}

bytes.AsMemory().CopyTo(memory);
int tempVal = Unsafe.As<float, int>(ref val);
SerializeInt32(memory.Span, tempVal);
}

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

BinaryPrimitives.WriteUInt16BigEndian(memory.Span, val);
SerializeUInt16(memory.Span, val);
}

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

BinaryPrimitives.WriteUInt32BigEndian(memory.Span, val);
SerializeUInt32(memory.Span, val);
}


[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void WriteUInt64(Memory<byte> memory, ulong val)
{
if (memory.Length < 8)
{
throw new ArgumentOutOfRangeException(nameof(memory), "Insufficient length to write UInt64 from memory.");
}

BinaryPrimitives.WriteUInt64BigEndian(memory.Span, val);
SerializeUInt64(memory.Span, val);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeInt16(Span<byte> memory, short val)
{
SerializeUInt16(memory, (ushort)val);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeUInt16(Span<byte> memory, ushort val)
{
memory[0] = (byte)((val >> 8) & 0xFF);
memory[1] = (byte)(val & 0xFF);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeInt32(Span<byte> memory, int val)
{
SerializeUInt32(memory, (uint)val);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeUInt32(Span<byte> memory, uint val)
{
memory[0] = (byte)((val >> 24) & 0xFF);
memory[1] = (byte)((val >> 16) & 0xFF);
memory[2] = (byte)((val >> 8) & 0xFF);
memory[3] = (byte)(val & 0xFF);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeInt64(Span<byte> memory, long val)
{
SerializeUInt64(memory, (ulong)val);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void SerializeUInt64(Span<byte> memory, ulong val)
{
memory[0] = (byte)((val >> 56) & 0xFF);
memory[1] = (byte)((val >> 48) & 0xFF);
memory[2] = (byte)((val >> 40) & 0xFF);
memory[3] = (byte)((val >> 32) & 0xFF);
memory[4] = (byte)((val >> 24) & 0xFF);
memory[5] = (byte)((val >> 16) & 0xFF);
memory[6] = (byte)((val >> 8) & 0xFF);
memory[7] = (byte)(val & 0xFF);
}
}
}