From 24e1334d7204fc96e3bf8cb06fae5f8353c67028 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 18 Mar 2017 16:57:15 +0100 Subject: [PATCH] PinnedBuffer and PinnedImageBuffer indexers --- .../Common/Memory/PinnedBuffer{T}.cs | 17 +++++ .../Common/Memory/PinnedImageBuffer{T}.cs | 9 +++ src/ImageSharp/Image/PixelAccessor{TColor}.cs | 20 +++--- .../Common/BufferSpanTests.cs | 56 +---------------- .../Common/PinnedBufferTests.cs | 48 +++++++++++--- .../Common/PinnedImageBufferTests.cs | 34 +++++++--- tests/ImageSharp.Tests/Common/TestStructs.cs | 62 +++++++++++++++++++ 7 files changed, 168 insertions(+), 78 deletions(-) create mode 100644 tests/ImageSharp.Tests/Common/TestStructs.cs diff --git a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs index d58354a71..611688c99 100644 --- a/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedBuffer{T}.cs @@ -104,6 +104,23 @@ namespace ImageSharp /// public BufferSpan Span => this; + /// + /// Returns a reference to specified element of the buffer. + /// + /// The index + /// The reference to the specified element + public unsafe ref T this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); + + byte* ptr = (byte*)this.Pointer + BufferSpan.SizeOf(index); + return ref Unsafe.AsRef(ptr); + } + } + /// /// Converts to an . /// diff --git a/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs index 6ec0fc4e5..380545d70 100644 --- a/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs +++ b/src/ImageSharp/Common/Memory/PinnedImageBuffer{T}.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Runtime.CompilerServices; /// /// Represents a pinned buffer of value type objects @@ -46,6 +47,14 @@ namespace ImageSharp /// public int Height { get; } + /// + /// Gets a reference to the element at the specified position. + /// + /// The x coordinate (row) + /// The y coordinate (position at row) + /// A reference to the element. + public ref T this[int x, int y] => ref this.Array[(this.Width * y) + x]; + /// /// Creates a clean instance of initializing it's elements with 'default(T)'. /// diff --git a/src/ImageSharp/Image/PixelAccessor{TColor}.cs b/src/ImageSharp/Image/PixelAccessor{TColor}.cs index e21e3aa46..cea058951 100644 --- a/src/ImageSharp/Image/PixelAccessor{TColor}.cs +++ b/src/ImageSharp/Image/PixelAccessor{TColor}.cs @@ -241,16 +241,16 @@ namespace ImageSharp this.CopyTo(area, sourceX, sourceY, width, height); } - /// - /// Gets a to the row 'y' beginning from the pixel at 'x'. - /// - /// The x coordinate - /// The y coordinate - /// The - internal BufferSpan GetRowSpan(int x, int y) - { - return this.pixelBuffer.Slice((y * this.Width) + x, this.Width - x); - } + ///// + ///// Gets a to the row 'y' beginning from the pixel at 'x'. + ///// + ///// The x coordinate + ///// The y coordinate + ///// The + //internal BufferSpan GetRowSpan(int x, int y) + //{ + // return this.pixelBuffer.Slice((y * this.Width) + x, this.Width - x); + //} /// /// Sets the pixel buffer in an unsafe manner. This should not be used unless you know what its doing!!! diff --git a/tests/ImageSharp.Tests/Common/BufferSpanTests.cs b/tests/ImageSharp.Tests/Common/BufferSpanTests.cs index 36cfe1b2a..aee032acc 100644 --- a/tests/ImageSharp.Tests/Common/BufferSpanTests.cs +++ b/tests/ImageSharp.Tests/Common/BufferSpanTests.cs @@ -7,62 +7,10 @@ namespace ImageSharp.Tests.Common using Xunit; + using static TestStructs; + public unsafe class BufferSpanTests { - public struct Foo - { - public int A; - - public double B; - - public Foo(int a, double b) - { - this.A = a; - this.B = b; - } - - internal static Foo[] CreateArray(int size) - { - Foo[] result = new Foo[size]; - for (int i = 0; i < size; i++) - { - result[i] = new Foo(i+1, i+1); - } - return result; - } - } - - /// - /// sizeof(AlignedFoo) == sizeof(long) - /// - public struct AlignedFoo - { - public int A; - - public int B; - - static AlignedFoo() - { - Assert.Equal(sizeof(AlignedFoo), sizeof(long)); - } - - public AlignedFoo(int a, int b) - { - this.A = a; - this.B = b; - } - - internal static AlignedFoo[] CreateArray(int size) - { - AlignedFoo[] result = new AlignedFoo[size]; - for (int i = 0; i < size; i++) - { - result[i] = new AlignedFoo(i + 1, i + 1); - } - return result; - } - } - [Fact] public void AsBytes() { diff --git a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs index f7189aadf..5e812d5a0 100644 --- a/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs +++ b/tests/ImageSharp.Tests/Common/PinnedBufferTests.cs @@ -7,15 +7,10 @@ using Xunit; + using static TestStructs; + public unsafe class PinnedBufferTests { - public struct Foo - { - public int A; - - public double B; - } - [Theory] [InlineData(42)] [InlineData(1111)] @@ -79,6 +74,45 @@ } } + public class Indexer + { + public static readonly TheoryData IndexerData = + new TheoryData() + { + { 10, 0 }, + { 16, 3 }, + { 10, 9 } + }; + + [Theory] + [MemberData(nameof(IndexerData))] + public void Read(int length, int index) + { + Foo[] a = Foo.CreateArray(length); + + using (PinnedBuffer buffer = new PinnedBuffer(a)) + { + Foo element = buffer[index]; + + Assert.Equal(a[index], element); + } + } + + [Theory] + [MemberData(nameof(IndexerData))] + public void Write(int length, int index) + { + Foo[] a = Foo.CreateArray(length); + + using (PinnedBuffer buffer = new PinnedBuffer(a)) + { + buffer[index] = new Foo(666, 666); + + Assert.Equal(new Foo(666, 666), a[index]); + } + } + } + [Fact] public void Dispose() { diff --git a/tests/ImageSharp.Tests/Common/PinnedImageBufferTests.cs b/tests/ImageSharp.Tests/Common/PinnedImageBufferTests.cs index fa9730798..7756b0aa9 100644 --- a/tests/ImageSharp.Tests/Common/PinnedImageBufferTests.cs +++ b/tests/ImageSharp.Tests/Common/PinnedImageBufferTests.cs @@ -5,6 +5,8 @@ namespace ImageSharp.Tests.Common using Xunit; + using static TestStructs; + public unsafe class PinnedImageBufferTests { [Theory] @@ -12,7 +14,7 @@ namespace ImageSharp.Tests.Common [InlineData(1025, 17)] public void Construct(int width, int height) { - using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) + using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); @@ -25,8 +27,8 @@ namespace ImageSharp.Tests.Common [InlineData(1025, 17)] public void Construct_FromExternalArray(int width, int height) { - int[] array = new int[width * height + 10]; - using (PinnedImageBuffer buffer = new PinnedImageBuffer(array, width, height)) + Foo[] array = new Foo[width * height + 10]; + using (PinnedImageBuffer buffer = new PinnedImageBuffer(array, width, height)) { Assert.Equal(width, buffer.Width); Assert.Equal(height, buffer.Height); @@ -57,9 +59,9 @@ namespace ImageSharp.Tests.Common [InlineData(17, 42, 41)] public void GetRowSpanY(int width, int height, int y) { - using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) + using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) { - BufferSpan span = buffer.GetRowSpan(y); + BufferSpan span = buffer.GetRowSpan(y); Assert.Equal(width * y, span.Start); Assert.Equal(width, span.Length); @@ -73,14 +75,32 @@ namespace ImageSharp.Tests.Common [InlineData(17, 42, 0, 41)] public void GetRowSpanXY(int width, int height, int x, int y) { - using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) + using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) { - BufferSpan span = buffer.GetRowSpan(x, y); + BufferSpan span = buffer.GetRowSpan(x, y); Assert.Equal(width * y + x, span.Start); Assert.Equal(width - x, span.Length); Assert.Equal(buffer.Pointer + sizeof(int) * (width * y + x), span.PointerAtOffset); } } + + [Theory] + [InlineData(42, 8, 0, 0)] + [InlineData(400, 1000, 20, 10)] + [InlineData(99, 88, 98, 87)] + public void Indexer(int width, int height, int x, int y) + { + using (PinnedImageBuffer buffer = new PinnedImageBuffer(width, height)) + { + Foo[] array = buffer.Array; + + ref Foo actual = ref buffer[x, y]; + + ref Foo expected = ref array[y * width + x]; + + Assert.True(Unsafe.AreSame(ref expected, ref actual)); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Common/TestStructs.cs b/tests/ImageSharp.Tests/Common/TestStructs.cs new file mode 100644 index 000000000..9e762bbd1 --- /dev/null +++ b/tests/ImageSharp.Tests/Common/TestStructs.cs @@ -0,0 +1,62 @@ +namespace ImageSharp.Tests.Common +{ + using Xunit; + + public static class TestStructs + { + public struct Foo + { + public int A; + + public double B; + + public Foo(int a, double b) + { + this.A = a; + this.B = b; + } + + internal static Foo[] CreateArray(int size) + { + Foo[] result = new Foo[size]; + for (int i = 0; i < size; i++) + { + result[i] = new Foo(i + 1, i + 1); + } + return result; + } + } + + + /// + /// sizeof(AlignedFoo) == sizeof(long) + /// + public unsafe struct AlignedFoo + { + public int A; + + public int B; + + static AlignedFoo() + { + Assert.Equal(sizeof(AlignedFoo), sizeof(long)); + } + + public AlignedFoo(int a, int b) + { + this.A = a; + this.B = b; + } + + internal static AlignedFoo[] CreateArray(int size) + { + AlignedFoo[] result = new AlignedFoo[size]; + for (int i = 0; i < size; i++) + { + result[i] = new AlignedFoo(i + 1, i + 1); + } + return result; + } + } + } +} \ No newline at end of file