Browse Source

introduce BufferArea2D, move Memory utility tests to proper place

pull/322/head
Anton Firszov 9 years ago
parent
commit
fcefa57b8b
  1. 2
      src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs
  2. 33
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/ComponentPostprocessor.cs
  3. 14
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockPostProcessor.cs
  4. 11
      src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs
  5. 14
      src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs
  6. 25
      src/ImageSharp/Memory/Buffer2DExtensions.cs
  7. 30
      src/ImageSharp/Memory/BufferArea2D.cs
  8. 38
      tests/ImageSharp.Tests/Memory/Buffer2DTests.cs
  9. 77
      tests/ImageSharp.Tests/Memory/BufferTests.cs
  10. 12
      tests/ImageSharp.Tests/Memory/Fast2DArrayTests.cs
  11. 11
      tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs
  12. 185
      tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
  13. 6
      tests/ImageSharp.Tests/Memory/TestStructs.cs

2
src/ImageSharp/Formats/Jpeg/Common/Block8x8.cs

@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Common
short* fp = blockPtr->data; short* fp = blockPtr->data;
fp[idx] = value; fp[idx] = value;
} }
public Block8x8F AsFloatBlock() public Block8x8F AsFloatBlock()
{ {
// TODO: Optimize this // TODO: Optimize this

33
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/ComponentPostprocessor.cs

@ -0,0 +1,33 @@
using System;
using SixLabors.ImageSharp.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
{
internal class ComponentPostProcessor : IDisposable
{
public Size ImageSizeInBlocks { get; }
public int NumberOfRowGroupScans
{
get;
}
class RowGroupProcessor : IDisposable
{
public Buffer2D<float> ColorBuffer { get; }
public void Dispose()
{
}
}
public void Dispose()
{
}
}
}

14
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockProcessor.cs → src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/JpegBlockPostProcessor.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
/// Encapsulates the implementation of processing "raw" <see cref="Buffer{T}"/>-s into Jpeg image channels. /// Encapsulates the implementation of processing "raw" <see cref="Buffer{T}"/>-s into Jpeg image channels.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal unsafe struct JpegBlockProcessor internal unsafe struct JpegBlockPostProcessor
{ {
/// <summary> /// <summary>
/// The <see cref="ComputationData"/> /// The <see cref="ComputationData"/>
@ -30,15 +30,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
private int componentIndex; private int componentIndex;
/// <summary> /// <summary>
/// Initialize the <see cref="JpegBlockProcessor"/> instance on the stack. /// Initialize the <see cref="JpegBlockPostProcessor"/> instance on the stack.
/// </summary> /// </summary>
/// <param name="processor">The <see cref="JpegBlockProcessor"/> instance</param> /// <param name="postProcessor">The <see cref="JpegBlockPostProcessor"/> instance</param>
/// <param name="componentIndex">The current component index</param> /// <param name="componentIndex">The current component index</param>
public static void Init(JpegBlockProcessor* processor, int componentIndex) public static void Init(JpegBlockPostProcessor* postProcessor, int componentIndex)
{ {
processor->componentIndex = componentIndex; postProcessor->componentIndex = componentIndex;
processor->data = ComputationData.Create(); postProcessor->data = ComputationData.Create();
processor->pointers = new DataPointers(&processor->data); postProcessor->pointers = new DataPointers(&postProcessor->data);
} }
/// <summary> /// <summary>

11
src/ImageSharp/Formats/Jpeg/GolangPort/Components/Decoder/OrigJpegScanDecoder.cs

@ -669,17 +669,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder
int val = bu >= 0 ? bu + delta : bu - delta; int val = bu >= 0 ? bu + delta : bu - delta;
Block8x8.SetScalarAt(b, u, (short)val); Block8x8.SetScalarAt(b, u, (short)val);
//if (bu >= 0)
//{
// // b[u] += delta;
// Block8x8.SetScalarAt(b, u, bu + delta);
//}
//else
//{
// // b[u] -= delta;
// Block8x8.SetScalarAt(b, u, bu - delta);
//}
} }
return zig; return zig;

14
src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs

@ -3,23 +3,21 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.GolangPort.Components.Decoder;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.MetaData.Profiles.Icc; using SixLabors.ImageSharp.MetaData.Profiles.Icc;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F; using Block8x8F = SixLabors.ImageSharp.Formats.Jpeg.Common.Block8x8F;
namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
{ {
using System.Linq;
using SixLabors.ImageSharp.Formats.Jpeg.Common;
using SixLabors.Primitives;
/// <summary> /// <summary>
/// Performs the jpeg decoding operation. /// Performs the jpeg decoding operation.
/// </summary> /// </summary>
@ -476,9 +474,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.ComponentCount, this.ComponentCount,
componentIndex => componentIndex =>
{ {
JpegBlockProcessor processor = default(JpegBlockProcessor); JpegBlockPostProcessor postProcessor = default(JpegBlockPostProcessor);
JpegBlockProcessor.Init(&processor, componentIndex); JpegBlockPostProcessor.Init(&postProcessor, componentIndex);
processor.ProcessAllBlocks(this); postProcessor.ProcessAllBlocks(this);
}); });
} }

25
src/ImageSharp/Memory/Buffer2DExtensions.cs

@ -3,6 +3,7 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
@ -39,5 +40,29 @@ namespace SixLabors.ImageSharp.Memory
{ {
return buffer.Span.Slice(y * buffer.Width, buffer.Width); return buffer.Span.Slice(y * buffer.Width, buffer.Width);
} }
/// <summary>
/// Returns the size of the buffer.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <returns>The <see cref="Size{T}"/> of the buffer</returns>
public static Size Size<T>(this IBuffer2D<T> buffer)
where T : struct
{
return new Size(buffer.Width, buffer.Height);
}
/// <summary>
/// Returns a <see cref="Rectangle"/> representing the full area of the buffer.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <param name="buffer">The <see cref="IBuffer2D{T}"/></param>
/// <returns>The <see cref="Rectangle"/></returns>
public static Rectangle FullRectangle<T>(this IBuffer2D<T> buffer)
where T : struct
{
return new Rectangle(0, 0, buffer.Width, buffer.Height);
}
} }
} }

30
src/ImageSharp/Memory/BufferArea2D.cs

@ -0,0 +1,30 @@
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;
}
}

38
tests/ImageSharp.Tests/Common/Buffer2DTests.cs → tests/ImageSharp.Tests/Memory/Buffer2DTests.cs

@ -1,14 +1,16 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; namespace SixLabors.ImageSharp.Tests.Memory
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using Xunit;
using static SixLabors.ImageSharp.Tests.Common.TestStructs;
namespace SixLabors.ImageSharp.Tests.Common
{ {
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tests.Common;
using Xunit;
public unsafe class Buffer2DTests public unsafe class Buffer2DTests
{ {
// ReSharper disable once ClassNeverInstantiated.Local // ReSharper disable once ClassNeverInstantiated.Local
@ -29,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1025, 17)] [InlineData(1025, 17)]
public void Construct(int width, int height) public void Construct(int width, int height)
{ {
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height)) using (Buffer2D<TestStructs.Foo> buffer = new Buffer2D<TestStructs.Foo>(width, height))
{ {
Assert.Equal(width, buffer.Width); Assert.Equal(width, buffer.Width);
Assert.Equal(height, buffer.Height); Assert.Equal(height, buffer.Height);
@ -42,8 +44,8 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1025, 17)] [InlineData(1025, 17)]
public void Construct_FromExternalArray(int width, int height) public void Construct_FromExternalArray(int width, int height)
{ {
Foo[] array = new Foo[width * height + 10]; TestStructs.Foo[] array = new TestStructs.Foo[width * height + 10];
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(array, width, height)) using (Buffer2D<TestStructs.Foo> buffer = new Buffer2D<TestStructs.Foo>(array, width, height))
{ {
Assert.Equal(width, buffer.Width); Assert.Equal(width, buffer.Width);
Assert.Equal(height, buffer.Height); Assert.Equal(height, buffer.Height);
@ -74,9 +76,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(17, 42, 41)] [InlineData(17, 42, 41)]
public void GetRowSpanY(int width, int height, int y) public void GetRowSpanY(int width, int height, int y)
{ {
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height)) using (Buffer2D<TestStructs.Foo> buffer = new Buffer2D<TestStructs.Foo>(width, height))
{ {
Span<Foo> span = buffer.GetRowSpan(y); Span<TestStructs.Foo> span = buffer.GetRowSpan(y);
// Assert.Equal(width * y, span.Start); // Assert.Equal(width * y, span.Start);
Assert.Equal(width, span.Length); Assert.Equal(width, span.Length);
@ -90,9 +92,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(17, 42, 0, 41)] [InlineData(17, 42, 0, 41)]
public void GetRowSpanXY(int width, int height, int x, int y) public void GetRowSpanXY(int width, int height, int x, int y)
{ {
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height)) using (Buffer2D<TestStructs.Foo> buffer = new Buffer2D<TestStructs.Foo>(width, height))
{ {
Span<Foo> span = buffer.GetRowSpan(x, y); Span<TestStructs.Foo> span = buffer.GetRowSpan(x, y);
// Assert.Equal(width * y + x, span.Start); // Assert.Equal(width * y + x, span.Start);
Assert.Equal(width - x, span.Length); Assert.Equal(width - x, span.Length);
@ -106,13 +108,13 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(99, 88, 98, 87)] [InlineData(99, 88, 98, 87)]
public void Indexer(int width, int height, int x, int y) public void Indexer(int width, int height, int x, int y)
{ {
using (Buffer2D<Foo> buffer = new Buffer2D<Foo>(width, height)) using (Buffer2D<TestStructs.Foo> buffer = new Buffer2D<TestStructs.Foo>(width, height))
{ {
Foo[] array = buffer.Array; TestStructs.Foo[] array = buffer.Array;
ref Foo actual = ref buffer[x, y]; ref TestStructs.Foo actual = ref buffer[x, y];
ref Foo expected = ref array[y * width + x]; ref TestStructs.Foo expected = ref array[y * width + x];
Assert.True(Unsafe.AreSame(ref expected, ref actual)); Assert.True(Unsafe.AreSame(ref expected, ref actual));
} }

77
tests/ImageSharp.Tests/Common/BufferTests.cs → tests/ImageSharp.Tests/Memory/BufferTests.cs

@ -1,16 +1,15 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; namespace SixLabors.ImageSharp.Tests.Memory
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using Xunit;
using static SixLabors.ImageSharp.Tests.Common.TestStructs;
namespace SixLabors.ImageSharp.Tests.Common
{ {
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using Xunit;
public unsafe class BufferTests public unsafe class BufferTests
{ {
// ReSharper disable once ClassNeverInstantiated.Local // ReSharper disable once ClassNeverInstantiated.Local
@ -36,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1111)] [InlineData(1111)]
public void ConstructWithOwnArray(int count) public void ConstructWithOwnArray(int count)
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(count)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(count))
{ {
Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.NotNull(buffer.Array); Assert.NotNull(buffer.Array);
@ -50,8 +49,8 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1111)] [InlineData(1111)]
public void ConstructWithExistingArray(int count) public void ConstructWithExistingArray(int count)
{ {
Foo[] array = new Foo[count]; TestStructs.Foo[] array = new TestStructs.Foo[count];
using (Buffer<Foo> buffer = new Buffer<Foo>(array)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(array))
{ {
Assert.False(buffer.IsDisposedOrLostArrayOwnership); Assert.False(buffer.IsDisposedOrLostArrayOwnership);
Assert.Equal(array, buffer.Array); Assert.Equal(array, buffer.Array);
@ -62,13 +61,13 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void Clear() public void Clear()
{ {
Foo[] a = { new Foo() { A = 1, B = 2 }, new Foo() { A = 3, B = 4 } }; TestStructs.Foo[] a = { new TestStructs.Foo() { A = 1, B = 2 }, new TestStructs.Foo() { A = 3, B = 4 } };
using (Buffer<Foo> buffer = new Buffer<Foo>(a)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(a))
{ {
buffer.Clear(); buffer.Clear();
Assert.Equal(default(Foo), a[0]); Assert.Equal(default(TestStructs.Foo), a[0]);
Assert.Equal(default(Foo), a[1]); Assert.Equal(default(TestStructs.Foo), a[1]);
} }
} }
@ -102,11 +101,11 @@ namespace SixLabors.ImageSharp.Tests.Common
[MemberData(nameof(IndexerData))] [MemberData(nameof(IndexerData))]
public void Read(int length, int index) public void Read(int length, int index)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
using (Buffer<Foo> buffer = new Buffer<Foo>(a)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(a))
{ {
Foo element = buffer[index]; TestStructs.Foo element = buffer[index];
Assert.Equal(a[index], element); Assert.Equal(a[index], element);
} }
@ -116,13 +115,13 @@ namespace SixLabors.ImageSharp.Tests.Common
[MemberData(nameof(IndexerData))] [MemberData(nameof(IndexerData))]
public void Write(int length, int index) public void Write(int length, int index)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
using (Buffer<Foo> buffer = new Buffer<Foo>(a)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(a))
{ {
buffer[index] = new Foo(666, 666); buffer[index] = new TestStructs.Foo(666, 666);
Assert.Equal(new Foo(666, 666), a[index]); Assert.Equal(new TestStructs.Foo(666, 666), a[index]);
} }
} }
} }
@ -130,7 +129,7 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void Dispose() public void Dispose()
{ {
Buffer<Foo> buffer = new Buffer<Foo>(42); Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42);
buffer.Dispose(); buffer.Dispose();
Assert.True(buffer.IsDisposedOrLostArrayOwnership); Assert.True(buffer.IsDisposedOrLostArrayOwnership);
@ -141,9 +140,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(123)] [InlineData(123)]
public void CastToSpan(int bufferLength) public void CastToSpan(int bufferLength)
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(bufferLength))
{ {
Span<Foo> span = buffer; Span<TestStructs.Foo> span = buffer;
//Assert.Equal(buffer.Array, span.ToArray()); //Assert.Equal(buffer.Array, span.ToArray());
//Assert.Equal(0, span.Start); //Assert.Equal(0, span.Start);
@ -155,9 +154,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void Span() public void Span()
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(42)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42))
{ {
Span<Foo> span = buffer.Span; Span<TestStructs.Foo> span = buffer.Span;
// Assert.Equal(buffer.Array, span.ToArray()); // Assert.Equal(buffer.Array, span.ToArray());
// Assert.Equal(0, span.Start); // Assert.Equal(0, span.Start);
@ -174,9 +173,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(123, 17)] [InlineData(123, 17)]
public void WithStartOnly(int bufferLength, int start) public void WithStartOnly(int bufferLength, int start)
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(bufferLength))
{ {
Span<Foo> span = buffer.Slice(start); Span<TestStructs.Foo> span = buffer.Slice(start);
Assert.SpanPointsTo(span, buffer, start); Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, bufferLength - start); Assert.Equal(span.Length, bufferLength - start);
@ -188,9 +187,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(123, 17, 42)] [InlineData(123, 17, 42)]
public void WithStartAndLength(int bufferLength, int start, int spanLength) public void WithStartAndLength(int bufferLength, int start, int spanLength)
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(bufferLength)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(bufferLength))
{ {
Span<Foo> span = buffer.Slice(start, spanLength); Span<TestStructs.Foo> span = buffer.Slice(start, spanLength);
Assert.SpanPointsTo(span, buffer, start); Assert.SpanPointsTo(span, buffer, start);
Assert.Equal(span.Length, spanLength); Assert.Equal(span.Length, spanLength);
@ -201,8 +200,8 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void UnPinAndTakeArrayOwnership() public void UnPinAndTakeArrayOwnership()
{ {
Foo[] data = null; TestStructs.Foo[] data = null;
using (Buffer<Foo> buffer = new Buffer<Foo>(42)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42))
{ {
data = buffer.TakeArrayOwnership(); data = buffer.TakeArrayOwnership();
Assert.True(buffer.IsDisposedOrLostArrayOwnership); Assert.True(buffer.IsDisposedOrLostArrayOwnership);
@ -217,10 +216,10 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void ReturnsPinnedPointerToTheBeginningOfArray() public void ReturnsPinnedPointerToTheBeginningOfArray()
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(42)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42))
{ {
Foo* actual = (Foo*)buffer.Pin(); TestStructs.Foo* actual = (TestStructs.Foo*)buffer.Pin();
fixed (Foo* expected = buffer.Array) fixed (TestStructs.Foo* expected = buffer.Array)
{ {
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }
@ -230,7 +229,7 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void SecondCallReturnsTheSamePointer() public void SecondCallReturnsTheSamePointer()
{ {
using (Buffer<Foo> buffer = new Buffer<Foo>(42)) using (Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42))
{ {
IntPtr ptr1 = buffer.Pin(); IntPtr ptr1 = buffer.Pin();
IntPtr ptr2 = buffer.Pin(); IntPtr ptr2 = buffer.Pin();
@ -242,7 +241,7 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void WhenCalledOnDisposedBuffer_ThrowsInvalidOperationException() public void WhenCalledOnDisposedBuffer_ThrowsInvalidOperationException()
{ {
Buffer<Foo> buffer = new Buffer<Foo>(42); Buffer<TestStructs.Foo> buffer = new Buffer<TestStructs.Foo>(42);
buffer.Dispose(); buffer.Dispose();
Assert.Throws<InvalidOperationException>(() => buffer.Pin()); Assert.Throws<InvalidOperationException>(() => buffer.Pin());

12
tests/ImageSharp.Tests/Common/Fast2DArrayTests.cs → tests/ImageSharp.Tests/Memory/Fast2DArrayTests.cs

@ -1,12 +1,14 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; namespace SixLabors.ImageSharp.Tests.Memory
using SixLabors.ImageSharp.Memory;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Common
{ {
using System;
using SixLabors.ImageSharp.Memory;
using Xunit;
public class Fast2DArrayTests public class Fast2DArrayTests
{ {
private static readonly float[,] FloydSteinbergMatrix = private static readonly float[,] FloydSteinbergMatrix =

11
tests/ImageSharp.Tests/Common/PixelDataPoolTests.cs → tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs

@ -1,14 +1,15 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System.Linq;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests namespace SixLabors.ImageSharp.Tests.Memory
{ {
using SixLabors.ImageSharp.Memory;
using Xunit;
/// <summary> /// <summary>
/// Tests the <see cref="PixelDataPool{T}"/> class. /// Tests the <see cref="PixelDataPool{T}"/> class.
/// </summary> /// </summary>

185
tests/ImageSharp.Tests/Common/BufferSpanTests.cs → tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs

@ -1,17 +1,18 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; namespace SixLabors.ImageSharp.Tests.Memory
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using static SixLabors.ImageSharp.Tests.Common.TestStructs;
namespace SixLabors.ImageSharp.Tests.Common
{ {
public unsafe class SpanTests using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tests.Common;
using Xunit;
public unsafe class SpanUtilityTests
{ {
// ReSharper disable once ClassNeverInstantiated.Local // ReSharper disable once ClassNeverInstantiated.Local
private class Assert : Xunit.Assert private class Assert : Xunit.Assert
@ -20,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Common
{ {
ref T1 bb = ref Unsafe.As<T2, T1>(ref b); ref T1 bb = ref Unsafe.As<T2, T1>(ref b);
True(Unsafe.AreSame(ref a, ref bb), "References are not same!"); Assert.True(Unsafe.AreSame(ref a, ref bb), "References are not same!");
} }
} }
@ -42,15 +43,15 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void AsBytes() public void AsBytes()
{ {
Foo[] fooz = { new Foo(1, 2), new Foo(3, 4), new Foo(5, 6) }; TestStructs.Foo[] fooz = { new TestStructs.Foo(1, 2), new TestStructs.Foo(3, 4), new TestStructs.Foo(5, 6) };
using (Buffer<Foo> colorBuf = new Buffer<Foo>(fooz)) using (Buffer<TestStructs.Foo> colorBuf = new Buffer<TestStructs.Foo>(fooz))
{ {
Span<Foo> orig = colorBuf.Slice(1); Span<TestStructs.Foo> orig = colorBuf.Slice(1);
Span<byte> asBytes = orig.AsBytes(); Span<byte> asBytes = orig.AsBytes();
// Assert.Equal(asBytes.Start, sizeof(Foo)); // Assert.Equal(asBytes.Start, sizeof(Foo));
Assert.Equal(orig.Length * Unsafe.SizeOf<Foo>(), asBytes.Length); Assert.Equal(orig.Length * Unsafe.SizeOf<TestStructs.Foo>(), asBytes.Length);
Assert.SameRefs(ref orig.DangerousGetPinnableReference(), ref asBytes.DangerousGetPinnableReference()); Assert.SameRefs(ref orig.DangerousGetPinnableReference(), ref asBytes.DangerousGetPinnableReference());
} }
} }
@ -60,10 +61,10 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void Basic() public void Basic()
{ {
Foo[] array = Foo.CreateArray(3); TestStructs.Foo[] array = TestStructs.Foo.CreateArray(3);
// Act: // Act:
Span<Foo> span = new Span<Foo>(array); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(array);
// Assert: // Assert:
Assert.Equal(array, span.ToArray()); Assert.Equal(array, span.ToArray());
@ -74,11 +75,11 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void WithStart() public void WithStart()
{ {
Foo[] array = Foo.CreateArray(4); TestStructs.Foo[] array = TestStructs.Foo.CreateArray(4);
int start = 2; int start = 2;
// Act: // Act:
Span<Foo> span = new Span<Foo>(array, start); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(array, start);
// Assert: // Assert:
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference()); Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
@ -88,11 +89,11 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void WithStartAndLength() public void WithStartAndLength()
{ {
Foo[] array = Foo.CreateArray(10); TestStructs.Foo[] array = TestStructs.Foo.CreateArray(10);
int start = 2; int start = 2;
int length = 3; int length = 3;
// Act: // Act:
Span<Foo> span = new Span<Foo>(array, start, length); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(array, start, length);
// Assert: // Assert:
Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference()); Assert.SameRefs(ref array[start], ref span.DangerousGetPinnableReference());
@ -105,12 +106,12 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void StartOnly() public void StartOnly()
{ {
Foo[] array = Foo.CreateArray(5); TestStructs.Foo[] array = TestStructs.Foo.CreateArray(5);
int start0 = 2; int start0 = 2;
int start1 = 2; int start1 = 2;
int totalOffset = start0 + start1; int totalOffset = start0 + start1;
Span<Foo> span = new Span<Foo>(array, start0); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(array, start0);
// Act: // Act:
span = span.Slice(start1); span = span.Slice(start1);
@ -123,13 +124,13 @@ namespace SixLabors.ImageSharp.Tests.Common
[Fact] [Fact]
public void StartAndLength() public void StartAndLength()
{ {
Foo[] array = Foo.CreateArray(10); TestStructs.Foo[] array = TestStructs.Foo.CreateArray(10);
int start0 = 2; int start0 = 2;
int start1 = 2; int start1 = 2;
int totalOffset = start0 + start1; int totalOffset = start0 + start1;
int sliceLength = 3; int sliceLength = 3;
Span<Foo> span = new Span<Foo>(array, start0); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(array, start0);
// Act: // Act:
span = span.Slice(start1, sliceLength); span = span.Slice(start1, sliceLength);
@ -176,10 +177,10 @@ namespace SixLabors.ImageSharp.Tests.Common
[MemberData(nameof(IndexerData))] [MemberData(nameof(IndexerData))]
public void Read(int length, int start, int index) public void Read(int length, int start, int index)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
Span<Foo> span = new Span<Foo>(a, start); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(a, start);
Foo element = span[index]; TestStructs.Foo element = span[index];
Assert.Equal(a[start + index], element); Assert.Equal(a[start + index], element);
} }
@ -188,12 +189,12 @@ namespace SixLabors.ImageSharp.Tests.Common
[MemberData(nameof(IndexerData))] [MemberData(nameof(IndexerData))]
public void Write(int length, int start, int index) public void Write(int length, int start, int index)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
Span<Foo> span = new Span<Foo>(a, start); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(a, start);
span[index] = new Foo(666, 666); span[index] = new TestStructs.Foo(666, 666);
Assert.Equal(new Foo(666, 666), a[start + index]); Assert.Equal(new TestStructs.Foo(666, 666), a[start + index]);
} }
[Theory] [Theory]
@ -203,15 +204,15 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(10, 1, 1, 7)] [InlineData(10, 1, 1, 7)]
public void AsBytes_Read(int length, int start, int index, int byteOffset) public void AsBytes_Read(int length, int start, int index, int byteOffset)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
Span<Foo> span = new Span<Foo>(a, start); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(a, start);
Span<byte> bytes = span.AsBytes(); Span<byte> bytes = span.AsBytes();
byte actual = bytes[index * Unsafe.SizeOf<Foo>() + byteOffset]; byte actual = bytes[index * Unsafe.SizeOf<TestStructs.Foo>() + byteOffset];
ref byte baseRef = ref Unsafe.As<Foo, byte>(ref a[0]); ref byte baseRef = ref Unsafe.As<TestStructs.Foo, byte>(ref a[0]);
byte expected = Unsafe.Add(ref baseRef, (start + index) * Unsafe.SizeOf<Foo>() + byteOffset); byte expected = Unsafe.Add(ref baseRef, (start + index) * Unsafe.SizeOf<TestStructs.Foo>() + byteOffset);
Assert.Equal(expected, actual); Assert.Equal(expected, actual);
} }
@ -223,9 +224,9 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(3, 4)] [InlineData(3, 4)]
public void DangerousGetPinnableReference(int start, int length) public void DangerousGetPinnableReference(int start, int length)
{ {
Foo[] a = Foo.CreateArray(length); TestStructs.Foo[] a = TestStructs.Foo.CreateArray(length);
Span<Foo> span = new Span<Foo>(a, start); Span<TestStructs.Foo> span = new Span<TestStructs.Foo>(a, start);
ref Foo r = ref span.DangerousGetPinnableReference(); ref TestStructs.Foo r = ref span.DangerousGetPinnableReference();
Assert.True(Unsafe.AreSame(ref a[start], ref r)); Assert.True(Unsafe.AreSame(ref a[start], ref r));
} }
@ -263,11 +264,11 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void GenericToOwnType(int count) public void GenericToOwnType(int count)
{ {
Foo[] source = Foo.CreateArray(count + 2); TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
Foo[] dest = new Foo[count + 5]; TestStructs.Foo[] dest = new TestStructs.Foo[count + 5];
Span<Foo> apSource = new Span<Foo>(source, 1); Span<TestStructs.Foo> apSource = new Span<TestStructs.Foo>(source, 1);
Span<Foo> apDest = new Span<Foo>(dest, 1); Span<TestStructs.Foo> apDest = new Span<TestStructs.Foo>(dest, 1);
SpanHelper.Copy(apSource, apDest, count - 1); SpanHelper.Copy(apSource, apDest, count - 1);
@ -286,11 +287,11 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void GenericToOwnType_Aligned(int count) public void GenericToOwnType_Aligned(int count)
{ {
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
AlignedFoo[] dest = new AlignedFoo[count + 5]; TestStructs.AlignedFoo[] dest = new TestStructs.AlignedFoo[count + 5];
Span<AlignedFoo> apSource = new Span<AlignedFoo>(source, 1); Span<TestStructs.AlignedFoo> apSource = new Span<TestStructs.AlignedFoo>(source, 1);
Span<AlignedFoo> apDest = new Span<AlignedFoo>(dest, 1); Span<TestStructs.AlignedFoo> apDest = new Span<TestStructs.AlignedFoo>(dest, 1);
SpanHelper.Copy(apSource, apDest, count - 1); SpanHelper.Copy(apSource, apDest, count - 1);
@ -332,22 +333,22 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void GenericToBytes(int count) public void GenericToBytes(int count)
{ {
int destCount = count * sizeof(Foo); int destCount = count * sizeof(TestStructs.Foo);
Foo[] source = Foo.CreateArray(count + 2); TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(Foo) * 2]; byte[] dest = new byte[destCount + sizeof(TestStructs.Foo) * 2];
Span<Foo> apSource = new Span<Foo>(source, 1); Span<TestStructs.Foo> apSource = new Span<TestStructs.Foo>(source, 1);
Span<byte> apDest = new Span<byte>(dest, sizeof(Foo)); Span<byte> apDest = new Span<byte>(dest, sizeof(TestStructs.Foo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(Foo)); SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.Foo));
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
Assert.False(ElementsAreEqual(source, dest, 0)); Assert.False((bool)ElementsAreEqual(source, dest, 0));
Assert.True(ElementsAreEqual(source, dest, 1)); Assert.True((bool)ElementsAreEqual(source, dest, 1));
Assert.True(ElementsAreEqual(source, dest, 2)); Assert.True((bool)ElementsAreEqual(source, dest, 2));
Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
Assert.False(ElementsAreEqual(source, dest, count)); Assert.False((bool)ElementsAreEqual(source, dest, count));
} }
[Theory] [Theory]
@ -355,22 +356,22 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void GenericToBytes_Aligned(int count) public void GenericToBytes_Aligned(int count)
{ {
int destCount = count * sizeof(Foo); int destCount = count * sizeof(TestStructs.Foo);
AlignedFoo[] source = AlignedFoo.CreateArray(count + 2); TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
byte[] dest = new byte[destCount + sizeof(AlignedFoo) * 2]; byte[] dest = new byte[destCount + sizeof(TestStructs.AlignedFoo) * 2];
Span<AlignedFoo> apSource = new Span<AlignedFoo>(source, 1); Span<TestStructs.AlignedFoo> apSource = new Span<TestStructs.AlignedFoo>(source, 1);
Span<byte> apDest = new Span<byte>(dest, sizeof(AlignedFoo)); Span<byte> apDest = new Span<byte>(dest, sizeof(TestStructs.AlignedFoo));
SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(AlignedFoo)); SpanHelper.Copy(apSource.AsBytes(), apDest, (count - 1) * sizeof(TestStructs.AlignedFoo));
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
Assert.False(ElementsAreEqual(source, dest, 0)); Assert.False((bool)ElementsAreEqual(source, dest, 0));
Assert.True(ElementsAreEqual(source, dest, 1)); Assert.True((bool)ElementsAreEqual(source, dest, 1));
Assert.True(ElementsAreEqual(source, dest, 2)); Assert.True((bool)ElementsAreEqual(source, dest, 2));
Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
Assert.False(ElementsAreEqual(source, dest, count)); Assert.False((bool)ElementsAreEqual(source, dest, count));
} }
[Theory] [Theory]
@ -389,9 +390,9 @@ namespace SixLabors.ImageSharp.Tests.Common
AssertNotDefault(source, 1); AssertNotDefault(source, 1);
Assert.True(ElementsAreEqual(source, dest, 0)); Assert.True((bool)ElementsAreEqual(source, dest, 0));
Assert.True(ElementsAreEqual(source, dest, count - 1)); Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
Assert.False(ElementsAreEqual(source, dest, count)); Assert.False((bool)ElementsAreEqual(source, dest, count));
} }
[Theory] [Theory]
@ -399,22 +400,22 @@ namespace SixLabors.ImageSharp.Tests.Common
[InlineData(1500)] [InlineData(1500)]
public void BytesToGeneric(int count) public void BytesToGeneric(int count)
{ {
int srcCount = count * sizeof(Foo); int srcCount = count * sizeof(TestStructs.Foo);
byte[] source = CreateTestBytes(srcCount); byte[] source = CreateTestBytes(srcCount);
Foo[] dest = new Foo[count + 2]; TestStructs.Foo[] dest = new TestStructs.Foo[count + 2];
Span<byte> apSource = new Span<byte>(source); Span<byte> apSource = new Span<byte>(source);
Span<Foo> apDest = new Span<Foo>(dest); Span<TestStructs.Foo> apDest = new Span<TestStructs.Foo>(dest);
SpanHelper.Copy(apSource, apDest.AsBytes(), count * sizeof(Foo)); SpanHelper.Copy(apSource, apDest.AsBytes(), count * sizeof(TestStructs.Foo));
AssertNotDefault(source, sizeof(Foo) + 1); AssertNotDefault(source, sizeof(TestStructs.Foo) + 1);
AssertNotDefault(dest, 1); AssertNotDefault(dest, 1);
Assert.True(ElementsAreEqual(dest, source, 0)); Assert.True((bool)ElementsAreEqual(dest, source, 0));
Assert.True(ElementsAreEqual(dest, source, 1)); Assert.True((bool)ElementsAreEqual(dest, source, 1));
Assert.True(ElementsAreEqual(dest, source, count - 1)); Assert.True((bool)ElementsAreEqual(dest, source, count - 1));
Assert.False(ElementsAreEqual(dest, source, count)); Assert.False((bool)ElementsAreEqual(dest, source, count));
} }
[Fact] [Fact]
@ -436,29 +437,29 @@ namespace SixLabors.ImageSharp.Tests.Common
} }
} }
internal static bool ElementsAreEqual(Foo[] array, byte[] rawArray, int index) internal static bool ElementsAreEqual(TestStructs.Foo[] array, byte[] rawArray, int index)
{ {
fixed (Foo* pArray = array) fixed (TestStructs.Foo* pArray = array)
fixed (byte* pRaw = rawArray) fixed (byte* pRaw = rawArray)
{ {
Foo* pCasted = (Foo*)pRaw; TestStructs.Foo* pCasted = (TestStructs.Foo*)pRaw;
Foo val1 = pArray[index]; TestStructs.Foo val1 = pArray[index];
Foo val2 = pCasted[index]; TestStructs.Foo val2 = pCasted[index];
return val1.Equals(val2); return val1.Equals(val2);
} }
} }
internal static bool ElementsAreEqual(AlignedFoo[] array, byte[] rawArray, int index) internal static bool ElementsAreEqual(TestStructs.AlignedFoo[] array, byte[] rawArray, int index)
{ {
fixed (AlignedFoo* pArray = array) fixed (TestStructs.AlignedFoo* pArray = array)
fixed (byte* pRaw = rawArray) fixed (byte* pRaw = rawArray)
{ {
AlignedFoo* pCasted = (AlignedFoo*)pRaw; TestStructs.AlignedFoo* pCasted = (TestStructs.AlignedFoo*)pRaw;
AlignedFoo val1 = pArray[index]; TestStructs.AlignedFoo val1 = pArray[index];
AlignedFoo val2 = pCasted[index]; TestStructs.AlignedFoo val2 = pCasted[index];
return val1.Equals(val2); return val1.Equals(val2);
} }

6
tests/ImageSharp.Tests/Common/TestStructs.cs → tests/ImageSharp.Tests/Memory/TestStructs.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using Xunit; namespace SixLabors.ImageSharp.Tests.Memory
namespace SixLabors.ImageSharp.Tests.Common
{ {
using Xunit;
public static class TestStructs public static class TestStructs
{ {
public struct Foo public struct Foo
Loading…
Cancel
Save