Browse Source

Implemented: CopyTo, TransformTo, TransformInplace

af/octree-no-pixelmap
Anton Firszov 6 years ago
parent
commit
7edc418141
  1. 46
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
  2. 9
      src/ImageSharp/Memory/TransformItemsDelegate{T}.cs
  3. 9
      src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs
  4. 50
      tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs
  5. 119
      tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs

46
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs

@ -38,6 +38,52 @@ namespace SixLabors.ImageSharp.Memory
}
}
public static void TransformTo<T>(
this IMemoryGroup<T> source,
IMemoryGroup<T> target,
TransformItemsDelegate<T> transform)
where T : struct
{
Guard.NotNull(source, nameof(source));
Guard.NotNull(target, nameof(target));
Guard.NotNull(transform, nameof(transform));
Guard.IsTrue(source.IsValid, nameof(source), "Source group must be valid.");
Guard.IsTrue(target.IsValid, nameof(target), "Target group must be valid.");
Guard.MustBeLessThanOrEqualTo(source.TotalLength, target.TotalLength, "Destination buffer too short!");
if (source.IsEmpty())
{
return;
}
long position = 0;
var srcCur = new MemoryGroupCursor<T>(source);
var trgCur = new MemoryGroupCursor<T>(target);
while (position < source.TotalLength)
{
int fwd = Math.Min(srcCur.LookAhead(), trgCur.LookAhead());
Span<T> srcSpan = srcCur.GetSpan(fwd);
Span<T> trgSpan = trgCur.GetSpan(fwd);
transform(srcSpan, trgSpan);
srcCur.Forward(fwd);
trgCur.Forward(fwd);
position += fwd;
}
}
public static void TransformInplace<T>(
this IMemoryGroup<T> memoryGroup,
TransformItemsInplaceDelegate<T> transform)
where T : struct
{
foreach (Memory<T> memory in memoryGroup)
{
transform(memory.Span);
}
}
public static bool IsEmpty<T>(this IMemoryGroup<T> group)
where T : struct
=> group.Count == 0;

9
src/ImageSharp/Memory/TransformItemsDelegate{T}.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Memory
{
internal delegate void TransformItemsDelegate<T>(ReadOnlySpan<T> source, Span<T> target);
}

9
src/ImageSharp/Memory/TransformItemsInplaceDelegate.cs

@ -0,0 +1,9 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Memory
{
internal delegate void TransformItemsInplaceDelegate<T>(Span<T> data);
}

50
tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.CopyTo.cs

@ -1,50 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers
{
public partial class MemoryGroupTests
{
public class CopyTo : MemoryGroupTestsBase
{
#pragma warning disable SA1509
public static readonly TheoryData<int, int, int, int> WhenSourceBufferIsShorterOrEqual_Data =
new TheoryData<int, int, int, int>()
{
{ 20, 10, 20, 10 },
{ 20, 5, 20, 4 },
{ 20, 4, 20, 5 },
{ 18, 6, 20, 5 },
{ 19, 10, 20, 10 },
{ 21, 10, 22, 2 },
{ 1, 5, 5, 4 },
{ 30, 12, 40, 5 },
{ 30, 5, 40, 12 },
};
[Theory]
[MemberData(nameof(WhenSourceBufferIsShorterOrEqual_Data))]
public void WhenSourceBufferIsShorterOrEqual(int srcTotal, int srcBufLen, int trgTotal, int trgBufLen)
{
using MemoryGroup<int> src = this.CreateTestGroup(srcTotal, srcBufLen, true);
using MemoryGroup<int> trg = this.CreateTestGroup(trgTotal, trgBufLen, false);
src.CopyTo(trg);
MemoryGroupIndex i = src.MinIndex();
MemoryGroupIndex j = trg.MinIndex();
for (; i < src.MaxIndex(); i += 1, j += 1)
{
int a = src.GetElementAt(i);
int b = src.GetElementAt(j);
Assert.Equal(a, b);
}
}
}
}
}

119
tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using Xunit;
@ -26,6 +27,124 @@ namespace SixLabors.ImageSharp.Tests.Memory.DiscontiguousBuffers
Assert.False(g.IsValid);
}
#pragma warning disable SA1509
private static readonly TheoryData<int, int, int, int> CopyAndTransformData =
new TheoryData<int, int, int, int>()
{
{ 20, 10, 20, 10 },
{ 20, 5, 20, 4 },
{ 20, 4, 20, 5 },
{ 18, 6, 20, 5 },
{ 19, 10, 20, 10 },
{ 21, 10, 22, 2 },
{ 1, 5, 5, 4 },
{ 30, 12, 40, 5 },
{ 30, 5, 40, 12 },
};
public class CopyTo : MemoryGroupTestsBase
{
public static readonly TheoryData<int, int, int, int> WhenSourceBufferIsShorterOrEqual_Data =
CopyAndTransformData;
[Theory]
[MemberData(nameof(WhenSourceBufferIsShorterOrEqual_Data))]
public void WhenSourceBufferIsShorterOrEqual(int srcTotal, int srcBufLen, int trgTotal, int trgBufLen)
{
using MemoryGroup<int> src = this.CreateTestGroup(srcTotal, srcBufLen, true);
using MemoryGroup<int> trg = this.CreateTestGroup(trgTotal, trgBufLen, false);
src.CopyTo(trg);
int pos = 0;
MemoryGroupIndex i = src.MinIndex();
MemoryGroupIndex j = trg.MinIndex();
for (; i < src.MaxIndex(); i += 1, j += 1, pos++)
{
int a = src.GetElementAt(i);
int b = trg.GetElementAt(j);
Assert.True(a == b, $"Mismatch @ {pos} Expected: {a} Actual: {b}");
}
}
[Fact]
public void WhenTargetBufferTooShort_Throws()
{
using MemoryGroup<int> src = this.CreateTestGroup(10, 20, true);
using MemoryGroup<int> trg = this.CreateTestGroup(5, 20, false);
Assert.Throws<ArgumentOutOfRangeException>(() => src.CopyTo(trg));
}
}
public class TransformTo : MemoryGroupTestsBase
{
public static readonly TheoryData<int, int, int, int> WhenSourceBufferIsShorterOrEqual_Data =
CopyAndTransformData;
[Theory]
[MemberData(nameof(WhenSourceBufferIsShorterOrEqual_Data))]
public void WhenSourceBufferIsShorterOrEqual(int srcTotal, int srcBufLen, int trgTotal, int trgBufLen)
{
using MemoryGroup<int> src = this.CreateTestGroup(srcTotal, srcBufLen, true);
using MemoryGroup<int> trg = this.CreateTestGroup(trgTotal, trgBufLen, false);
src.TransformTo(trg, MultiplyAllBy2);
int pos = 0;
MemoryGroupIndex i = src.MinIndex();
MemoryGroupIndex j = trg.MinIndex();
for (; i < src.MaxIndex(); i += 1, j += 1, pos++)
{
int a = src.GetElementAt(i);
int b = trg.GetElementAt(j);
Assert.True(b == 2 * a, $"Mismatch @ {pos} Expected: {a} Actual: {b}");
}
}
[Fact]
public void WhenTargetBufferTooShort_Throws()
{
using MemoryGroup<int> src = this.CreateTestGroup(10, 20, true);
using MemoryGroup<int> trg = this.CreateTestGroup(5, 20, false);
Assert.Throws<ArgumentOutOfRangeException>(() => src.TransformTo(trg, MultiplyAllBy2));
}
}
[Theory]
[InlineData(100, 5)]
[InlineData(100, 101)]
public void TransformInplace(int totalLength, int bufferLength)
{
using MemoryGroup<int> src = this.CreateTestGroup(10, 20, true);
src.TransformInplace(s => MultiplyAllBy2(s, s));
int cnt = 1;
for (MemoryGroupIndex i = src.MinIndex(); i < src.MaxIndex(); i += 1)
{
int val = src.GetElementAt(i);
Assert.Equal(expected: cnt * 2, val);
cnt++;
}
}
private static void MultiplyAllBy2(ReadOnlySpan<int> source, Span<int> target)
{
Assert.Equal(source.Length, target.Length);
for (int k = 0; k < source.Length; k++)
{
target[k] = source[k] * 2;
}
}
[StructLayout(LayoutKind.Sequential, Size = 5)]
private struct S5
{

Loading…
Cancel
Save