Browse Source

implemented BufferArea<T>

af/merge-core
Anton Firszov 9 years ago
parent
commit
d06a014d12
  1. 19
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  2. 63
      src/ImageSharp/Memory/BufferArea.cs
  3. 30
      src/ImageSharp/Memory/BufferArea2D.cs
  4. 2
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  5. 102
      tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

19
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -64,5 +64,24 @@ namespace SixLabors.ImageSharp.Memory
{
return new Rectangle(0, 0, buffer.Width, buffer.Height);
}
/// <summary>
/// Return a <see cref="BufferArea{T}"/> to the subarea represented by 'rectangle'
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <param name="rectangle">The rectangel subarea</param>
/// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer, Rectangle rectangle)
where T : struct => new BufferArea<T>(buffer, rectangle);
/// <summary>
/// Return a <see cref="BufferArea{T}"/> to the whole area of 'buffer'
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <returns>The <see cref="BufferArea{T}"/></returns>
public static BufferArea<T> GetArea<T>(this IBuffer2D<T> buffer)
where T : struct => new BufferArea<T>(buffer);
}
}

63
src/ImageSharp/Memory/BufferArea.cs

@ -0,0 +1,63 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>).
/// This type is kind-of 2D Span, but it can live on heap.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
internal struct BufferArea<T>
where T : struct
{
public readonly Rectangle Rectangle;
public BufferArea(IBuffer2D<T> destinationBuffer, Rectangle rectangle)
{
Guard.MustBeGreaterThanOrEqualTo(rectangle.X, 0, nameof(rectangle));
Guard.MustBeGreaterThanOrEqualTo(rectangle.Y, 0, nameof(rectangle));
Guard.MustBeLessThan(rectangle.Width, destinationBuffer.Width, nameof(rectangle));
Guard.MustBeLessThan(rectangle.Height, destinationBuffer.Height, nameof(rectangle));
this.DestinationBuffer = destinationBuffer;
this.Rectangle = rectangle;
}
public BufferArea(IBuffer2D<T> destinationBuffer)
: this(destinationBuffer, destinationBuffer.FullRectangle())
{
}
public IBuffer2D<T> DestinationBuffer { get; }
public Size Size => this.Rectangle.Size;
public ref T this[int x, int y] => ref this.DestinationBuffer.Span[this.GetIndexOf(x, y)];
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> GetRowSpan(int y)
{
int yy = this.GetRowIndex(y);
int xx = this.Rectangle.X;
int width = this.Rectangle.Width;
return this.DestinationBuffer.Span.Slice(yy + xx, width);
}
[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)]
private int GetRowIndex(int y)
{
return (y + this.Rectangle.Y) * this.DestinationBuffer.Width;
}
}
}

30
src/ImageSharp/Memory/BufferArea2D.cs

@ -1,30 +0,0 @@
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Represents a rectangular area inside a 2D memory buffer. (Most commonly <see cref="Buffer2D{T}"/>)
/// This type is kind-of 2D Span.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
internal struct BufferArea2D<T>
where T : struct
{
public IBuffer2D<T> DestinationBuffer { get; }
public readonly Rectangle Rectangle;
public BufferArea2D(IBuffer2D<T> destinationBuffer, Rectangle rectangle)
{
this.DestinationBuffer = destinationBuffer;
this.Rectangle = rectangle;
}
public BufferArea2D(Buffer2D<T> destinationBuffer)
: this(destinationBuffer, destinationBuffer.FullRectangle())
{
}
public Size Size => this.Rectangle.Size;
}
}

2
tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Tests.Memory
using Xunit;
public unsafe class Buffer2DTests
public class Buffer2DTests
{
// ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert

102
tests/ImageSharp.Tests/Memory/BufferAreaTests.cs

@ -0,0 +1,102 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Memory
{
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
using Xunit;
public class BufferAreaTests
{
[Fact]
public void Construct()
{
using (var buffer = new Buffer2D<int>(10, 20))
{
var rectangle = new Rectangle(3,2, 5, 6);
var area = new BufferArea<int>(buffer, rectangle);
Assert.Equal(buffer, area.DestinationBuffer);
Assert.Equal(rectangle, area.Rectangle);
}
}
private static Buffer2D<int> CreateTestBuffer(int w, int h)
{
var buffer = new Buffer2D<int>(w, h);
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
buffer[x, y] = y * 100 + x;
}
}
return buffer;
}
[Theory]
[InlineData(-1, 1, 0, 0)]
[InlineData(1, -1, 0, 0)]
[InlineData(0, 0, 1, 0)]
[InlineData(0, 0, 0, 42)]
public void Construct_WhenRectangleIsOutsideOfBufferBoundaries_Throws(int dx, int dy, int dWidth, int dHeight)
{
using (var buffer = new Buffer2D<int>(10, 20))
{
Rectangle r = buffer.FullRectangle();
r = new Rectangle(r.X+dx, r.Y+dy, r.Width + dWidth, r.Height + dHeight );
Assert.ThrowsAny<ArgumentException>(
() =>
{
var area = new BufferArea<int>(buffer, r);
});
}
}
[Theory]
[InlineData(2, 3, 2, 2)]
[InlineData(5, 4, 3, 2)]
public void Indexer(int rx, int ry, int x, int y)
{
using (Buffer2D<int> buffer = CreateTestBuffer(20, 30))
{
Rectangle r = new Rectangle(rx, ry, 5, 6);
BufferArea<int> area = buffer.GetArea(r);
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)
{
using (Buffer2D<int> buffer = CreateTestBuffer(20, 30))
{
Rectangle r = new Rectangle(rx, ry, w, h);
BufferArea<int> area = buffer.GetArea(r);
Span<int> span = area.GetRowSpan(y);
Assert.Equal(w, span.Length);
for (int i = 0; i < w; i++)
{
int expected = (ry + y) * 100 + rx + i;
int value = span[i];
Assert.Equal(expected, value);
}
}
}
}
}
Loading…
Cancel
Save