From b4b3074738b43d4d4ca47c3d72c29560798411f7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 19 Aug 2020 14:39:01 +0100 Subject: [PATCH] Optimize Write(Span) --- src/ImageSharp/IO/ChunkedMemoryStream.cs | 36 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/IO/ChunkedMemoryStream.cs b/src/ImageSharp/IO/ChunkedMemoryStream.cs index bd374a3ce4..233154e9e0 100644 --- a/src/ImageSharp/IO/ChunkedMemoryStream.cs +++ b/src/ImageSharp/IO/ChunkedMemoryStream.cs @@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.IO if (value < 0) { - throw new ArgumentOutOfRangeException(nameof(value)); + ThrowArgumentOutOfRange(nameof(value)); } // Back up current position in case new position is out of range @@ -167,12 +167,13 @@ namespace SixLabors.ImageSharp.IO // Position is out of range this.readChunk = backupReadChunk; this.readOffset = backupReadOffset; - throw new ArgumentOutOfRangeException(nameof(value)); + ThrowArgumentOutOfRange(nameof(value)); } } } /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override long Seek(long offset, SeekOrigin origin) { this.EnsureNotDisposed(); @@ -231,6 +232,7 @@ namespace SixLabors.ImageSharp.IO } /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int Read(byte[] buffer, int offset, int count) { Guard.NotNull(buffer, nameof(buffer)); @@ -243,6 +245,7 @@ namespace SixLabors.ImageSharp.IO #if SUPPORTS_SPAN_STREAM /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int Read(Span buffer) => this.ReadImpl(buffer); #endif @@ -303,6 +306,7 @@ namespace SixLabors.ImageSharp.IO } /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int ReadByte() { this.EnsureNotDisposed(); @@ -342,7 +346,17 @@ namespace SixLabors.ImageSharp.IO } /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override void Write(byte[] buffer, int offset, int count) + => this.WriteImpl(buffer.AsSpan().Slice(offset, count)); + +#if SUPPORTS_SPAN_STREAM + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public override void Write(ReadOnlySpan buffer) => this.WriteImpl(buffer); +#endif + + private void WriteImpl(ReadOnlySpan buffer) { this.EnsureNotDisposed(); @@ -353,9 +367,10 @@ namespace SixLabors.ImageSharp.IO this.writeOffset = 0; } - byte[] chunkBuffer = this.writeChunk.Buffer.Array; + Span chunkBuffer = this.writeChunk.Buffer.GetSpan(); int chunkSize = this.writeChunk.Length; - + int count = buffer.Length; + int offset = 0; while (count > 0) { if (this.writeOffset == chunkSize) @@ -364,12 +379,13 @@ namespace SixLabors.ImageSharp.IO this.writeChunk.Next = this.AllocateMemoryChunk(); this.writeChunk = this.writeChunk.Next; this.writeOffset = 0; - chunkBuffer = this.writeChunk.Buffer.Array; + chunkBuffer = this.writeChunk.Buffer.GetSpan(); chunkSize = this.writeChunk.Length; } int copyCount = Math.Min(count, chunkSize - this.writeOffset); - Buffer.BlockCopy(buffer, offset, chunkBuffer, this.writeOffset, copyCount); + buffer.Slice(offset, copyCount).CopyTo(chunkBuffer.Slice(this.writeOffset)); + offset += copyCount; count -= copyCount; this.writeOffset += copyCount; @@ -493,9 +509,11 @@ namespace SixLabors.ImageSharp.IO [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowDisposed() - { - throw new ObjectDisposedException(null, "The stream is closed."); - } + => throw new ObjectDisposedException(null, "The stream is closed."); + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ThrowArgumentOutOfRange(string value) + => throw new ArgumentOutOfRangeException(value); [MethodImpl(MethodImplOptions.AggressiveInlining)] private MemoryChunk AllocateMemoryChunk()