Skip to content

BinaryWriter perf improvements #99775

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

Closed
wants to merge 7 commits into from
Closed
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
80 changes: 50 additions & 30 deletions src/libraries/System.Private.CoreLib/src/System/IO/BinaryWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Buffers;
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
Expand Down Expand Up @@ -135,18 +136,27 @@ public virtual long Seek(int offset, SeekOrigin origin)
// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
//
public virtual void Write(bool value) => OutStream.WriteByte((byte)(value ? 1 : 0));
public virtual void Write(bool value)
{
OutStream.WriteByte((byte)(value ? 1 : 0));
}

// Writes a byte to this stream. The current position of the stream is
// advanced by one.
//
public virtual void Write(byte value) => OutStream.WriteByte(value);
public virtual void Write(byte value)
{
OutStream.WriteByte(value);
}

// Writes a signed byte to this stream. The current position of the stream
// is advanced by one.
//
[CLSCompliant(false)]
public virtual void Write(sbyte value) => OutStream.WriteByte((byte)value);
public virtual void Write(sbyte value)
{
OutStream.WriteByte((byte)value);
}

// Writes a byte array to this stream.
//
Expand Down Expand Up @@ -243,9 +253,14 @@ public virtual void Write(char[] chars, int index, int count)
//
public virtual void Write(double value)
{
Span<byte> buffer = stackalloc byte[sizeof(double)];
BinaryPrimitives.WriteDoubleLittleEndian(buffer, value);
OutStream.Write(buffer);
if (BitConverter.IsLittleEndian)
{
WriteBytes(value);
}
else
{
WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.DoubleToUInt64Bits(value)));
}
}

public virtual void Write(decimal value)
Expand All @@ -260,9 +275,7 @@ public virtual void Write(decimal value)
//
public virtual void Write(short value)
{
Span<byte> buffer = stackalloc byte[sizeof(short)];
BinaryPrimitives.WriteInt16LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? (ushort)value : BinaryPrimitives.ReverseEndianness((ushort)value));
}

// Writes a two-byte unsigned integer to this stream. The current position
Expand All @@ -271,19 +284,15 @@ public virtual void Write(short value)
[CLSCompliant(false)]
public virtual void Write(ushort value)
{
Span<byte> buffer = stackalloc byte[sizeof(ushort)];
BinaryPrimitives.WriteUInt16LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value));
}

// Writes a four-byte signed integer to this stream. The current position
// of the stream is advanced by four.
//
public virtual void Write(int value)
{
Span<byte> buffer = stackalloc byte[sizeof(int)];
BinaryPrimitives.WriteInt32LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? (uint)value : BinaryPrimitives.ReverseEndianness((uint)value));
}

// Writes a four-byte unsigned integer to this stream. The current position
Expand All @@ -292,19 +301,15 @@ public virtual void Write(int value)
[CLSCompliant(false)]
public virtual void Write(uint value)
{
Span<byte> buffer = stackalloc byte[sizeof(uint)];
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value));
}

// Writes an eight-byte signed integer to this stream. The current position
// of the stream is advanced by eight.
//
public virtual void Write(long value)
{
Span<byte> buffer = stackalloc byte[sizeof(long)];
BinaryPrimitives.WriteInt64LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? (ulong)value : BinaryPrimitives.ReverseEndianness((ulong)value));
}

// Writes an eight-byte unsigned integer to this stream. The current
Expand All @@ -313,29 +318,44 @@ public virtual void Write(long value)
[CLSCompliant(false)]
public virtual void Write(ulong value)
{
Span<byte> buffer = stackalloc byte[sizeof(ulong)];
BinaryPrimitives.WriteUInt64LittleEndian(buffer, value);
OutStream.Write(buffer);
WriteBytes(BitConverter.IsLittleEndian ? value : BinaryPrimitives.ReverseEndianness(value));
}

// Writes a float to this stream. The current position of the stream is
// advanced by four.
//
public virtual void Write(float value)
{
Span<byte> buffer = stackalloc byte[sizeof(float)];
BinaryPrimitives.WriteSingleLittleEndian(buffer, value);
OutStream.Write(buffer);
if (BitConverter.IsLittleEndian)
{
WriteBytes(value);
}
else
{
WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.SingleToUInt32Bits(value)));
}
}

// Writes a half to this stream. The current position of the stream is
// advanced by two.
//
public virtual void Write(Half value)
{
Span<byte> buffer = stackalloc byte[sizeof(ushort) /* = sizeof(Half) */];
BinaryPrimitives.WriteHalfLittleEndian(buffer, value);
OutStream.Write(buffer);
if (BitConverter.IsLittleEndian)
{
WriteBytes(value);
}
else
{
WriteBytes(BinaryPrimitives.ReverseEndianness(BitConverter.HalfToUInt16Bits(value)));
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void WriteBytes<T>(T value)
where T : unmanaged
{
OutStream.Write(MemoryMarshal.AsBytes(new ReadOnlySpan<T>(in value)));
}

// Writes a length-prefixed string to this stream in the BinaryWriter's
Expand Down