diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferArea{T}.cs
index 983d6b3a76..b9210e301f 100644
--- a/src/ImageSharp/Memory/BufferArea{T}.cs
+++ b/src/ImageSharp/Memory/BufferArea{T}.cs
@@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.Memory
/// The position inside a row
/// The row index
/// The reference to the value
- public ref T this[int x, int y] => ref this.DestinationBuffer.GetSingleSpan()[this.GetIndexOf(x, y)];
+ public ref T this[int x, int y] => ref this.DestinationBuffer[x + this.Rectangle.X, y + this.Rectangle.Y];
///
/// Gets a reference to the [0,0] element.
@@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Memory
/// The reference to the [0,0] element
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetReferenceToOrigin() =>
- ref this.DestinationBuffer.GetSingleSpan()[(this.Rectangle.Y * this.DestinationBuffer.Width) + this.Rectangle.X];
+ ref this.GetRowSpan(0)[0];
///
/// Gets a span to row 'y' inside this area.
@@ -94,16 +94,16 @@ namespace SixLabors.ImageSharp.Memory
int xx = this.Rectangle.X;
int width = this.Rectangle.Width;
- return this.DestinationBuffer.GetSingleSpan().Slice(yy + xx, width);
+ return this.DestinationBuffer.MemoryGroup.GetBoundedSlice(yy + xx, width).Span;
}
///
/// Returns a sub-area as . (Similar to .)
///
- /// The x index at the subarea origo
- /// The y index at the subarea origo
- /// The desired width of the subarea
- /// The desired height of the subarea
+ /// The x index at the subarea origin.
+ /// The y index at the subarea origin.
+ /// The desired width of the subarea.
+ /// The desired height of the subarea.
/// The subarea
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public BufferArea GetSubArea(int x, int y, int width, int height)
@@ -129,14 +129,6 @@ namespace SixLabors.ImageSharp.Memory
return new BufferArea(this.DestinationBuffer, rectangle);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int GetIndexOf(int x, int y)
- {
- int yy = this.GetRowIndex(y);
- int xx = this.Rectangle.X + x;
- return yy + xx;
- }
-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal int GetRowIndex(int y)
{
@@ -148,7 +140,7 @@ namespace SixLabors.ImageSharp.Memory
// Optimization for when the size of the area is the same as the buffer size.
if (this.IsFullBufferArea)
{
- this.DestinationBuffer.GetSingleSpan().Clear();
+ this.DestinationBuffer.MemoryGroup.Clear();
return;
}
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
index ce719dc910..1b4c297f39 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
@@ -7,6 +7,24 @@ namespace SixLabors.ImageSharp.Memory
{
internal static class MemoryGroupExtensions
{
+ public static void Fill(this IMemoryGroup group, T value)
+ where T : struct
+ {
+ foreach (Memory memory in group)
+ {
+ memory.Span.Fill(value);
+ }
+ }
+
+ public static void Clear(this IMemoryGroup group)
+ where T : struct
+ {
+ foreach (Memory memory in group)
+ {
+ memory.Span.Clear();
+ }
+ }
+
///
/// Returns a slice that is expected to be within the bounds of a single buffer.
/// Otherwise is thrown.
diff --git a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs
index a0112ce901..77e899a4c2 100644
--- a/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs
+++ b/tests/ImageSharp.Tests/Memory/BufferAreaTests.cs
@@ -9,22 +9,22 @@ namespace SixLabors.ImageSharp.Tests.Memory
{
public class BufferAreaTests
{
+ private readonly TestMemoryAllocator memoryAllocator = new TestMemoryAllocator();
+
[Fact]
public void Construct()
{
- using (var buffer = Configuration.Default.MemoryAllocator.Allocate2D(10, 20))
- {
- var rectangle = new Rectangle(3, 2, 5, 6);
- var area = new BufferArea(buffer, rectangle);
+ using Buffer2D buffer = this.memoryAllocator.Allocate2D(10, 20);
+ var rectangle = new Rectangle(3, 2, 5, 6);
+ var area = new BufferArea(buffer, rectangle);
- Assert.Equal(buffer, area.DestinationBuffer);
- Assert.Equal(rectangle, area.Rectangle);
- }
+ Assert.Equal(buffer, area.DestinationBuffer);
+ Assert.Equal(rectangle, area.Rectangle);
}
- private static Buffer2D CreateTestBuffer(int w, int h)
+ private Buffer2D CreateTestBuffer(int w, int h)
{
- var buffer = Configuration.Default.MemoryAllocator.Allocate2D(w, h);
+ Buffer2D buffer = this.memoryAllocator.Allocate2D(w, h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
@@ -37,110 +37,122 @@ namespace SixLabors.ImageSharp.Tests.Memory
}
[Theory]
- [InlineData(2, 3, 2, 2)]
- [InlineData(5, 4, 3, 2)]
- public void Indexer(int rx, int ry, int x, int y)
+ [InlineData(1000, 2, 3, 2, 2)]
+ [InlineData(1000, 5, 4, 3, 2)]
+ [InlineData(200, 2, 3, 2, 2)]
+ [InlineData(200, 5, 4, 3, 2)]
+ public void Indexer(int bufferCapacity, int rx, int ry, int x, int y)
{
- using (Buffer2D buffer = CreateTestBuffer(20, 30))
- {
- var r = new Rectangle(rx, ry, 5, 6);
+ this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
+ using Buffer2D buffer = this.CreateTestBuffer(20, 30);
+ var r = new Rectangle(rx, ry, 5, 6);
- BufferArea area = buffer.GetArea(r);
+ BufferArea area = buffer.GetArea(r);
- int value = area[x, y];
- int expected = ((ry + y) * 100) + rx + x;
- Assert.Equal(expected, value);
- }
+ int value = area[x, y];
+ int expected = ((ry + y) * 100) + rx + x;
+ Assert.Equal(expected, value);
}
[Theory]
- [InlineData(2, 3, 2, 5, 6)]
- [InlineData(5, 4, 3, 6, 5)]
- public void GetRowSpan(int rx, int ry, int y, int w, int h)
+ [InlineData(1000, 2, 3, 2, 5, 6)]
+ [InlineData(1000, 5, 4, 3, 6, 5)]
+ [InlineData(200, 2, 3, 2, 5, 6)]
+ [InlineData(200, 5, 4, 3, 6, 5)]
+ public void GetRowSpan(int bufferCapacity, int rx, int ry, int y, int w, int h)
{
- using (Buffer2D buffer = CreateTestBuffer(20, 30))
- {
- var r = new Rectangle(rx, ry, w, h);
+ this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
- BufferArea area = buffer.GetArea(r);
+ using Buffer2D buffer = this.CreateTestBuffer(20, 30);
+ var r = new Rectangle(rx, ry, w, h);
- Span span = area.GetRowSpan(y);
+ BufferArea area = buffer.GetArea(r);
- Assert.Equal(w, span.Length);
+ Span span = area.GetRowSpan(y);
- for (int i = 0; i < w; i++)
- {
- int expected = ((ry + y) * 100) + rx + i;
- int value = span[i];
+ Assert.Equal(w, span.Length);
- Assert.Equal(expected, value);
- }
+ for (int i = 0; i < w; i++)
+ {
+ int expected = ((ry + y) * 100) + rx + i;
+ int value = span[i];
+
+ Assert.Equal(expected, value);
}
}
[Fact]
public void GetSubArea()
{
- using (Buffer2D buffer = CreateTestBuffer(20, 30))
- {
- BufferArea area0 = buffer.GetArea(6, 8, 10, 10);
+ using Buffer2D buffer = this.CreateTestBuffer(20, 30);
+ BufferArea area0 = buffer.GetArea(6, 8, 10, 10);
- BufferArea area1 = area0.GetSubArea(4, 4, 5, 5);
+ BufferArea area1 = area0.GetSubArea(4, 4, 5, 5);
- var expectedRect = new Rectangle(10, 12, 5, 5);
+ var expectedRect = new Rectangle(10, 12, 5, 5);
- Assert.Equal(buffer, area1.DestinationBuffer);
- Assert.Equal(expectedRect, area1.Rectangle);
+ Assert.Equal(buffer, area1.DestinationBuffer);
+ Assert.Equal(expectedRect, area1.Rectangle);
- int value00 = (12 * 100) + 10;
- Assert.Equal(value00, area1[0, 0]);
- }
+ int value00 = (12 * 100) + 10;
+ Assert.Equal(value00, area1[0, 0]);
}
- [Fact]
- public void DangerousGetPinnableReference()
+ [Theory]
+ [InlineData(1000)]
+ [InlineData(40)]
+ public void GetReferenceToOrigin(int bufferCapacity)
{
- using (Buffer2D buffer = CreateTestBuffer(20, 30))
- {
- BufferArea area0 = buffer.GetArea(6, 8, 10, 10);
+ this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
- ref int r = ref area0.GetReferenceToOrigin();
+ using Buffer2D buffer = this.CreateTestBuffer(20, 30);
+ BufferArea area0 = buffer.GetArea(6, 8, 10, 10);
- int expected = buffer[6, 8];
- Assert.Equal(expected, r);
- }
+ ref int r = ref area0.GetReferenceToOrigin();
+
+ int expected = buffer[6, 8];
+ Assert.Equal(expected, r);
}
- [Fact]
- public void Clear_FullArea()
+ [Theory]
+ [InlineData(1000)]
+ [InlineData(70)]
+ public void Clear_FullArea(int bufferCapacity)
{
- using (Buffer2D buffer = CreateTestBuffer(22, 13))
+ this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
+
+ using Buffer2D buffer = this.CreateTestBuffer(22, 13);
+ var emptyRow = new int[22];
+ buffer.GetArea().Clear();
+
+ for (int y = 0; y < 13; y++)
{
- buffer.GetArea().Clear();
- Span fullSpan = buffer.GetSingleSpan();
- Assert.True(fullSpan.SequenceEqual(new int[fullSpan.Length]));
+ Span row = buffer.GetRowSpan(y);
+ Assert.True(row.SequenceEqual(emptyRow));
}
}
- [Fact]
- public void Clear_SubArea()
+ [Theory]
+ [InlineData(1000)]
+ [InlineData(40)]
+ public void Clear_SubArea(int bufferCapacity)
{
- using (Buffer2D buffer = CreateTestBuffer(20, 30))
- {
- BufferArea area = buffer.GetArea(5, 5, 10, 10);
- area.Clear();
+ this.memoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity;
- Assert.NotEqual(0, buffer[4, 4]);
- Assert.NotEqual(0, buffer[15, 15]);
+ using Buffer2D buffer = this.CreateTestBuffer(20, 30);
+ BufferArea area = buffer.GetArea(5, 5, 10, 10);
+ area.Clear();
- Assert.Equal(0, buffer[5, 5]);
- Assert.Equal(0, buffer[14, 14]);
+ Assert.NotEqual(0, buffer[4, 4]);
+ Assert.NotEqual(0, buffer[15, 15]);
- for (int y = area.Rectangle.Y; y < area.Rectangle.Bottom; y++)
- {
- Span span = buffer.GetRowSpan(y).Slice(area.Rectangle.X, area.Width);
- Assert.True(span.SequenceEqual(new int[area.Width]));
- }
+ Assert.Equal(0, buffer[5, 5]);
+ Assert.Equal(0, buffer[14, 14]);
+
+ for (int y = area.Rectangle.Y; y < area.Rectangle.Bottom; y++)
+ {
+ Span span = buffer.GetRowSpan(y).Slice(area.Rectangle.X, area.Width);
+ Assert.True(span.SequenceEqual(new int[area.Width]));
}
}
}
diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs
index bf081cb557..694c4d32f6 100644
--- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs
+++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Buffers;
+using System.Linq;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using Xunit;
@@ -163,6 +164,32 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers
Assert.ThrowsAny(() => group.GetBoundedSlice(start, length));
}
+ [Fact]
+ public void Fill()
+ {
+ using MemoryGroup group = this.CreateTestGroup(100, 10, true);
+ group.Fill(42);
+
+ int[] expectedRow = Enumerable.Repeat(42, 10).ToArray();
+ foreach (Memory memory in group)
+ {
+ Assert.True(memory.Span.SequenceEqual(expectedRow));
+ }
+ }
+
+ [Fact]
+ public void Clear()
+ {
+ using MemoryGroup group = this.CreateTestGroup(100, 10, true);
+ group.Clear();
+
+ var expectedRow = new int[10];
+ foreach (Memory memory in group)
+ {
+ Assert.True(memory.Span.SequenceEqual(expectedRow));
+ }
+ }
+
private static void MultiplyAllBy2(ReadOnlySpan source, Span target)
{
Assert.Equal(source.Length, target.Length);