From 6a2bd3d617a70d4c30d8846e46be9549efa08c4d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 19 Feb 2018 18:03:35 +0100 Subject: [PATCH] introducing FakeBuffer workaround --- .../Processors/FillRegionProcessor.cs | 4 +- .../Memory/ArrayPoolMemoryManager.cs | 6 +- src/ImageSharp/Memory/FakeBuffer.cs | 64 +++++++++++++++++++ src/ImageSharp/Memory/MemoryManager.cs | 16 ++++- .../Memory/SimpleManagedMemoryManager.cs | 4 +- 5 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 src/ImageSharp/Memory/FakeBuffer.cs diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs index d5bc401074..fc3f289abf 100644 --- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs @@ -99,8 +99,8 @@ namespace SixLabors.ImageSharp.Drawing.Processors using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options)) { int scanlineWidth = maxX - minX; - using (var buffer = source.MemoryManager.Allocate(maxIntersections)) - using (var scanline = source.MemoryManager.Allocate(scanlineWidth)) + using (FakeBuffer buffer = source.MemoryManager.AllocateFake(maxIntersections)) + using (FakeBuffer scanline = source.MemoryManager.AllocateFake(scanlineWidth)) { bool scanlineDirty = true; for (int y = minY; y < maxY; y++) diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs index 86776fd358..0cb1e38f8a 100644 --- a/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs +++ b/src/ImageSharp/Memory/ArrayPoolMemoryManager.cs @@ -38,13 +38,13 @@ namespace SixLabors.ImageSharp.Memory } /// - internal override Buffer Allocate(int itemCount, bool clear) + internal override Buffer Allocate(int length, bool clear) { int itemSizeBytes = Unsafe.SizeOf(); - int bufferSizeInBytes = itemCount * itemSizeBytes; + int bufferSizeInBytes = length * itemSizeBytes; byte[] byteBuffer = this.pool.Rent(bufferSizeInBytes); - var buffer = new Buffer(Unsafe.As(byteBuffer), itemCount, this); + var buffer = new Buffer(Unsafe.As(byteBuffer), length, this); if (clear) { buffer.Clear(); diff --git a/src/ImageSharp/Memory/FakeBuffer.cs b/src/ImageSharp/Memory/FakeBuffer.cs new file mode 100644 index 0000000000..e4bc4e463c --- /dev/null +++ b/src/ImageSharp/Memory/FakeBuffer.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Memory +{ + /// + /// Temporal workaround providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery. + /// + internal class FakeBuffer : IBuffer + where T : struct + { + public FakeBuffer(T[] array) + { + this.Array = array; + } + + public T[] Array { get; } + + public Span Span => this.Array; + + public int Length => this.Array.Length; + + /// + /// Returns a reference to specified element of the buffer. + /// + /// The index + /// The reference to the specified element + public ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); + + Span span = this.Span; + return ref span[index]; + } + } + + /// + /// Converts to an . + /// + /// The to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator ReadOnlySpan(FakeBuffer buffer) + { + return new ReadOnlySpan(buffer.Array, 0, buffer.Length); + } + + /// + /// Converts to an . + /// + /// The to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Span(FakeBuffer buffer) + { + return new Span(buffer.Array, 0, buffer.Length); + } + + public void Dispose() + { + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Memory/MemoryManager.cs b/src/ImageSharp/Memory/MemoryManager.cs index 6be7012e6a..6bad01cea3 100644 --- a/src/ImageSharp/Memory/MemoryManager.cs +++ b/src/ImageSharp/Memory/MemoryManager.cs @@ -12,14 +12,14 @@ namespace SixLabors.ImageSharp.Memory public abstract class MemoryManager { /// - /// Allocates a of size , optionally + /// Allocates a of size , optionally /// clearing the buffer before it gets returned. /// /// Type of the data stored in the buffer - /// Size of the buffer to allocate + /// Size of the buffer to allocate /// True to clear the backing memory of the buffer /// A buffer of values of type . - internal abstract Buffer Allocate(int size, bool clear) + internal abstract Buffer Allocate(int length, bool clear) where T : struct; /// @@ -30,5 +30,15 @@ namespace SixLabors.ImageSharp.Memory /// The buffer to release internal abstract void Release(Buffer buffer) where T : struct; + + /// + /// Temporal workaround. A method providing a "Buffer" based on a generic array without the 'Unsafe.As()' hackery. + /// Should be replaced with 'Allocate()' as soon as SixLabors.Shapes has Span-based API-s! + /// + internal FakeBuffer AllocateFake(int length) + where T : struct + { + return new FakeBuffer(new T[length]); + } } } diff --git a/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs b/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs index 2aefe898fd..7a92d6c9fb 100644 --- a/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs +++ b/src/ImageSharp/Memory/SimpleManagedMemoryManager.cs @@ -6,9 +6,9 @@ public class SimpleManagedMemoryManager : MemoryManager { /// - internal override Buffer Allocate(int size, bool clear) + internal override Buffer Allocate(int length, bool clear) { - return new Buffer(new T[size], size); + return new Buffer(new T[length], length); } ///