From 6c1ed4d2c19d1c29d1cfde0e6556732609d35c17 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Thu, 22 Mar 2018 08:32:02 -0700 Subject: [PATCH] Remove BitConverter from EndianBinaryWriter & add Floating point tests --- src/ImageSharp/IO/EndianBinaryWriter.cs | 86 +++++++++++++++---- .../IO/EndianBitConverter.GetBytes.cs | 12 --- .../IO/EndianBinaryReaderWriterTests.cs | 41 ++++++++- 3 files changed, 107 insertions(+), 32 deletions(-) diff --git a/src/ImageSharp/IO/EndianBinaryWriter.cs b/src/ImageSharp/IO/EndianBinaryWriter.cs index fc6434020..10df3f9a6 100644 --- a/src/ImageSharp/IO/EndianBinaryWriter.cs +++ b/src/ImageSharp/IO/EndianBinaryWriter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers.Binary; using System.IO; using System.Text; @@ -23,6 +24,11 @@ namespace SixLabors.ImageSharp.IO /// private readonly char[] charBuffer = new char[1]; + /// + /// The endianness used to write the data + /// + private readonly Endianness endianness; + /// /// Whether or not this writer has been disposed yet. /// @@ -55,8 +61,8 @@ namespace SixLabors.ImageSharp.IO Guard.IsTrue(stream.CanWrite, nameof(stream), "Stream isn't writable"); this.BaseStream = stream; - this.BitConverter = EndianBitConverter.GetConverter(endianness); this.Encoding = encoding; + this.endianness = endianness; } /// @@ -69,11 +75,6 @@ namespace SixLabors.ImageSharp.IO /// public Stream BaseStream { get; } - /// - /// Gets the bit converter used to write values to the stream - /// - internal EndianBitConverter BitConverter { get; } - /// /// Closes the writer, including the underlying stream. /// @@ -108,7 +109,8 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(bool value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + this.buffer[0] = value ? (byte)1 : (byte)0; + this.WriteInternal(this.buffer, 1); } @@ -119,7 +121,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(short value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteInt16BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteInt16LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 2); } @@ -130,7 +140,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(int value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteInt32BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteInt32LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 4); } @@ -141,7 +159,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(long value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteInt64BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteInt64LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 8); } @@ -152,7 +178,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(ushort value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteUInt16BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteUInt16LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 2); } @@ -163,7 +197,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(uint value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteUInt32BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteUInt32LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 4); } @@ -174,7 +216,15 @@ namespace SixLabors.ImageSharp.IO /// The value to write public void Write(ulong value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); + if (this.endianness == Endianness.BigEndian) + { + BinaryPrimitives.WriteUInt64BigEndian(this.buffer, value); + } + else + { + BinaryPrimitives.WriteUInt64LittleEndian(this.buffer, value); + } + this.WriteInternal(this.buffer, 8); } @@ -183,10 +233,9 @@ namespace SixLabors.ImageSharp.IO /// for this writer. 4 bytes are written. /// /// The value to write - public void Write(float value) + public unsafe void Write(float value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); - this.WriteInternal(this.buffer, 4); + this.Write(*((int*)&value)); } /// @@ -194,10 +243,9 @@ namespace SixLabors.ImageSharp.IO /// for this writer. 8 bytes are written. /// /// The value to write - public void Write(double value) + public unsafe void Write(double value) { - this.BitConverter.CopyBytes(value, this.buffer, 0); - this.WriteInternal(this.buffer, 8); + this.Write(*((long*)&value)); } /// diff --git a/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs index 5686c829c..e133cf7f4 100644 --- a/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs +++ b/src/ImageSharp/IO/EndianBitConverter.GetBytes.cs @@ -121,17 +121,5 @@ namespace SixLabors.ImageSharp.IO { return this.GetBytes(*((int*)&value)); } - - /// - /// Returns the specified decimal value as an array of bytes. - /// - /// The number to convert. - /// An array of bytes with length 16. - public byte[] GetBytes(decimal value) - { - byte[] result = new byte[16]; - this.CopyBytes(value, result, 0); - return result; - } } } diff --git a/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs b/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs index 6c639693a..6e22b1689 100644 --- a/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs +++ b/tests/ImageSharp.Tests/IO/EndianBinaryReaderWriterTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.IO; using SixLabors.ImageSharp.IO; using Xunit; @@ -9,6 +10,44 @@ namespace SixLabors.ImageSharp.Tests.IO { public class EndianBinaryReaderWriterTests { + [Fact] + public void RoundtripSingles() + { + foreach ((Endianness endianness, byte[] bytes) in new[] { + (Endianness.BigEndian, new byte[] { 64, 73, 15, 219 }), + (Endianness.LittleEndian, new byte[] { 219, 15, 73, 64 }) + }) + { + var stream = new MemoryStream(); + + using (var writer = new EndianBinaryWriter(endianness, stream)) + { + writer.Write((float)Math.PI); + + Assert.Equal(bytes, stream.ToArray()); + } + } + } + + [Fact] + public void RoundtripDoubles() + { + foreach ((Endianness endianness, byte[] bytes) in new[] { + (Endianness.BigEndian, new byte[] { 64, 9, 33, 251, 84, 68, 45, 24 }), + (Endianness.LittleEndian, new byte[] { 24, 45, 68, 84, 251, 33, 9, 64 }) + }) + { + var stream = new MemoryStream(); + + using (var writer = new EndianBinaryWriter(endianness, stream)) + { + writer.Write(Math.PI); + + Assert.Equal(bytes, stream.ToArray()); + } + } + } + /// /// Ensures that the data written through a binary writer can be read back through the reader /// @@ -55,4 +94,4 @@ namespace SixLabors.ImageSharp.Tests.IO } } } -} +} \ No newline at end of file