diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
index 661f33e081..4bae31bcae 100644
--- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
+++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
@@ -37,7 +37,7 @@
-
+
diff --git a/src/ImageSharp/Common/Extensions/StreamExtensions.cs b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
index d11ba8ca57..7952dfb083 100644
--- a/src/ImageSharp/Common/Extensions/StreamExtensions.cs
+++ b/src/ImageSharp/Common/Extensions/StreamExtensions.cs
@@ -4,6 +4,8 @@
using System;
using System.IO;
+using SixLabors.Memory;
+
namespace SixLabors.ImageSharp
{
///
@@ -69,5 +71,15 @@ namespace SixLabors.ImageSharp
}
}
}
+
+ public static void Read(this Stream stream, IManagedByteBuffer buffer)
+ {
+ stream.Read(buffer.Array, 0, buffer.Length());
+ }
+
+ public static void Write(this Stream stream, IManagedByteBuffer buffer)
+ {
+ stream.Write(buffer.Array, 0, buffer.Length());
+ }
}
}
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index eca1341015..7a56dcaba4 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -35,7 +35,7 @@
-
+
All
diff --git a/src/ImageSharp/Memory/AllocationOptions.cs b/src/ImageSharp/Memory/AllocationOptions.cs
deleted file mode 100644
index 5eda00505e..0000000000
--- a/src/ImageSharp/Memory/AllocationOptions.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.Memory
-{
- ///
- /// Options for allocating buffers.
- ///
- public enum AllocationOptions
- {
- ///
- /// Indicates that the buffer should just be allocated.
- ///
- None,
-
- ///
- /// Indicates that the allocated buffer should be cleaned following allocation.
- ///
- Clean
- }
-}
diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs
deleted file mode 100644
index adc8843a3c..0000000000
--- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.Buffer{T}.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Buffers;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.Memory
-{
- ///
- /// Contains and
- ///
- public partial class ArrayPoolMemoryAllocator
- {
- ///
- /// The buffer implementation of .
- ///
- private class Buffer : ManagedBufferBase
- where T : struct
- {
- ///
- /// The length of the buffer
- ///
- private readonly int length;
-
- ///
- /// A weak reference to the source pool.
- ///
- ///
- /// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
- /// after a call to , regardless of having buffer instances still being in use.
- ///
- private WeakReference> sourcePoolReference;
-
- public Buffer(byte[] data, int length, ArrayPool sourcePool)
- {
- this.Data = data;
- this.length = length;
- this.sourcePoolReference = new WeakReference>(sourcePool);
- }
-
- ///
- /// Gets the buffer as a byte array.
- ///
- protected byte[] Data { get; private set; }
-
- ///
- protected override void Dispose(bool disposing)
- {
- if (!disposing || this.Data == null || this.sourcePoolReference == null)
- {
- return;
- }
-
- if (this.sourcePoolReference.TryGetTarget(out ArrayPool pool))
- {
- pool.Return(this.Data);
- }
-
- this.sourcePoolReference = null;
- this.Data = null;
- }
-
- public override Span GetSpan() => MemoryMarshal.Cast(this.Data.AsSpan()).Slice(0, this.length);
-
- protected override object GetPinnableObject() => this.Data;
- }
-
- ///
- /// The implementation of .
- ///
- private class ManagedByteBuffer : Buffer, IManagedByteBuffer
- {
- public ManagedByteBuffer(byte[] data, int length, ArrayPool sourcePool)
- : base(data, length, sourcePool)
- {
- }
-
- public byte[] Array => this.Data;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
deleted file mode 100644
index 78d6e27b21..0000000000
--- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.Memory
-{
- ///
- /// Contains common factory methods and configuration constants.
- ///
- public partial class ArrayPoolMemoryAllocator
- {
- ///
- /// The default value for: maximum size of pooled arrays in bytes.
- /// Currently set to 24MB, which is equivalent to 8 megapixels of raw data.
- ///
- internal const int DefaultMaxPooledBufferSizeInBytes = 24 * 1024 * 1024;
-
- ///
- /// The value for: The threshold to pool arrays in which has less buckets for memory safety.
- ///
- private const int DefaultBufferSelectorThresholdInBytes = 8 * 1024 * 1024;
-
- ///
- /// The default bucket count for .
- ///
- private const int DefaultLargePoolBucketCount = 6;
-
- ///
- /// The default bucket count for .
- ///
- private const int DefaultNormalPoolBucketCount = 16;
-
- ///
- /// This is the default. Should be good for most use cases.
- ///
- /// The memory manager
- public static ArrayPoolMemoryAllocator CreateDefault()
- {
- return new ArrayPoolMemoryAllocator(
- DefaultMaxPooledBufferSizeInBytes,
- DefaultBufferSelectorThresholdInBytes,
- DefaultLargePoolBucketCount,
- DefaultNormalPoolBucketCount);
- }
-
- ///
- /// For environments with limited memory capabilities. Only small images are pooled, which can result in reduced througput.
- ///
- /// The memory manager
- public static ArrayPoolMemoryAllocator CreateWithModeratePooling()
- {
- return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24);
- }
-
- ///
- /// Only pool small buffers like image rows.
- ///
- /// The memory manager
- public static ArrayPoolMemoryAllocator CreateWithMinimalPooling()
- {
- return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24);
- }
-
- ///
- /// RAM is not an issue for me, gimme maximum througput!
- ///
- /// The memory manager
- public static ArrayPoolMemoryAllocator CreateWithAggressivePooling()
- {
- return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs
deleted file mode 100644
index 32c1c6d1d8..0000000000
--- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Buffers;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.Memory
-{
- ///
- /// Implements by allocating memory from .
- ///
- public sealed partial class ArrayPoolMemoryAllocator : MemoryAllocator
- {
- ///
- /// The for small-to-medium buffers which is not kept clean.
- ///
- private ArrayPool normalArrayPool;
-
- ///
- /// The for huge buffers, which is not kept clean.
- ///
- private ArrayPool largeArrayPool;
-
- private readonly int maxArraysPerBucketNormalPool;
-
- private readonly int maxArraysPerBucketLargePool;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ArrayPoolMemoryAllocator()
- : this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes)
- : this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes))
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- /// Arrays over this threshold will be pooled in which has less buckets for memory safety.
- public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
- : this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- /// The threshold to pool arrays in which has less buckets for memory safety.
- /// Max arrays per bucket for the large array pool
- /// Max arrays per bucket for the normal array pool
- public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool)
- {
- ImageSharp.Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
- Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes));
-
- this.MaxPoolSizeInBytes = maxPoolSizeInBytes;
- this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes;
- this.maxArraysPerBucketLargePool = maxArraysPerBucketLargePool;
- this.maxArraysPerBucketNormalPool = maxArraysPerBucketNormalPool;
-
- this.InitArrayPools();
- }
-
- ///
- /// Gets the maximum size of pooled arrays in bytes.
- ///
- public int MaxPoolSizeInBytes { get; }
-
- ///
- /// Gets the threshold to pool arrays in which has less buckets for memory safety.
- ///
- public int PoolSelectorThresholdInBytes { get; }
-
- ///
- public override void ReleaseRetainedResources()
- {
- this.InitArrayPools();
- }
-
- ///
- internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
- {
- int itemSizeBytes = Unsafe.SizeOf();
- int bufferSizeInBytes = length * itemSizeBytes;
-
- ArrayPool pool = this.GetArrayPool(bufferSizeInBytes);
- byte[] byteArray = pool.Rent(bufferSizeInBytes);
-
- var buffer = new Buffer(byteArray, length, pool);
- if (options == AllocationOptions.Clean)
- {
- buffer.Clear();
- }
-
- return buffer;
- }
-
- ///
- internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options)
- {
- ArrayPool pool = this.GetArrayPool(length);
- byte[] byteArray = pool.Rent(length);
-
- var buffer = new ManagedByteBuffer(byteArray, length, pool);
- if (options == AllocationOptions.Clean)
- {
- buffer.Clear();
- }
-
- return buffer;
- }
-
- private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes)
- {
- return maxPoolSizeInBytes / 4;
- }
-
- private ArrayPool GetArrayPool(int bufferSizeInBytes)
- {
- return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool;
- }
-
- private void InitArrayPools()
- {
- this.largeArrayPool = ArrayPool.Create(this.MaxPoolSizeInBytes, this.maxArraysPerBucketLargePool);
- this.normalArrayPool = ArrayPool.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool);
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/BasicArrayBuffer.cs b/src/ImageSharp/Memory/BasicArrayBuffer.cs
deleted file mode 100644
index f40df76049..0000000000
--- a/src/ImageSharp/Memory/BasicArrayBuffer.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.Memory
-{
- ///
- /// Wraps an array as an instance.
- ///
- internal class BasicArrayBuffer : ManagedBufferBase
- where T : struct
- {
- public BasicArrayBuffer(T[] array, int length)
- {
- ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
- this.Array = array;
- this.Length = length;
- }
-
- public BasicArrayBuffer(T[] array)
- : this(array, array.Length)
- {
- }
-
- public T[] Array { get; }
-
- public int Length { get; }
-
- ///
- /// Returns a reference to specified element of the buffer.
- ///
- /// The index
- /// The reference to the specified element
- public ref T this[int index]
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- DebugGuard.MustBeLessThan(index, this.Length, nameof(index));
-
- Span span = this.GetSpan();
- return ref span[index];
- }
- }
-
- protected override void Dispose(bool disposing)
- {
- }
-
- public override Span GetSpan() => this.Array.AsSpan(0, this.Length);
-
- protected override object GetPinnableObject()
- {
- return this.Array;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/BasicByteBuffer.cs b/src/ImageSharp/Memory/BasicByteBuffer.cs
deleted file mode 100644
index 9f995e347f..0000000000
--- a/src/ImageSharp/Memory/BasicByteBuffer.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.Memory
-{
- internal sealed class BasicByteBuffer : BasicArrayBuffer, IManagedByteBuffer
- {
- internal BasicByteBuffer(byte[] array)
- : base(array)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/IManagedByteBuffer.cs b/src/ImageSharp/Memory/IManagedByteBuffer.cs
deleted file mode 100644
index 91c61424b0..0000000000
--- a/src/ImageSharp/Memory/IManagedByteBuffer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Buffers;
-
-namespace SixLabors.Memory
-{
- ///
- /// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.
- ///
- internal interface IManagedByteBuffer : IMemoryOwner
- {
- ///
- /// Gets the managed array backing this buffer instance.
- ///
- byte[] Array { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/ManagedBufferBase.cs b/src/ImageSharp/Memory/ManagedBufferBase.cs
deleted file mode 100644
index 8aaf199ffd..0000000000
--- a/src/ImageSharp/Memory/ManagedBufferBase.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Buffers;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.Memory
-{
- ///
- /// Provides a base class for implementations by implementing pinning logic for adaption.
- ///
- internal abstract class ManagedBufferBase : MemoryManager
- where T : struct
- {
- private GCHandle pinHandle;
-
- public bool IsMemoryOwner => true;
-
- ///
- /// Gets the object that should be pinned.
- ///
- protected abstract object GetPinnableObject();
-
- public override unsafe MemoryHandle Pin(int elementIndex = 0)
- {
- if (!this.pinHandle.IsAllocated)
- {
- this.pinHandle = GCHandle.Alloc(this.GetPinnableObject(), GCHandleType.Pinned);
- }
-
- void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
- return new MemoryHandle(ptr, this.pinHandle);
- }
-
- public override void Unpin()
- {
- if (this.pinHandle.IsAllocated)
- {
- this.pinHandle.Free();
- }
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/MemoryAllocator.cs b/src/ImageSharp/Memory/MemoryAllocator.cs
deleted file mode 100644
index 57b721e483..0000000000
--- a/src/ImageSharp/Memory/MemoryAllocator.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Buffers;
-
-namespace SixLabors.Memory
-{
- ///
- /// Memory managers are used to allocate memory for image processing operations.
- ///
- public abstract class MemoryAllocator
- {
- ///
- /// Allocates an , holding a of length .
- ///
- /// Type of the data stored in the buffer
- /// Size of the buffer to allocate
- /// The allocation options.
- /// A buffer of values of type .
- internal abstract IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
- where T : struct;
-
- ///
- /// Allocates an .
- ///
- /// The requested buffer length
- /// The allocation options.
- /// The
- internal abstract IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None);
-
- ///
- /// Releases all retained resources not being in use.
- /// Eg: by resetting array pools and letting GC to free the arrays.
- ///
- public virtual void ReleaseRetainedResources()
- {
- }
- }
-}
diff --git a/src/ImageSharp/Memory/BufferExtensions.cs b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs
similarity index 85%
rename from src/ImageSharp/Memory/BufferExtensions.cs
rename to src/ImageSharp/Memory/MemoryOwnerExtensions.cs
index 800e0d975a..1010a01c6b 100644
--- a/src/ImageSharp/Memory/BufferExtensions.cs
+++ b/src/ImageSharp/Memory/MemoryOwnerExtensions.cs
@@ -9,7 +9,10 @@ using System.Runtime.InteropServices;
namespace SixLabors.Memory
{
- internal static class BufferExtensions
+ ///
+ /// Extension methods for
+ ///
+ internal static class MemoryOwnerExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Span GetSpan(this IMemoryOwner buffer)
@@ -57,15 +60,5 @@ namespace SixLabors.Memory
public static ref T GetReference(this IMemoryOwner buffer)
where T : struct =>
ref MemoryMarshal.GetReference(buffer.GetSpan());
-
- public static void Read(this Stream stream, IManagedByteBuffer buffer)
- {
- stream.Read(buffer.Array, 0, buffer.Length());
- }
-
- public static void Write(this Stream stream, IManagedByteBuffer buffer)
- {
- stream.Write(buffer.Array, 0, buffer.Length());
- }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs
deleted file mode 100644
index 612b538202..0000000000
--- a/src/ImageSharp/Memory/SimpleGcMemoryAllocator.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using System.Buffers;
-
-namespace SixLabors.Memory
-{
- ///
- /// Implements by newing up arrays by the GC on every allocation requests.
- ///
- public sealed class SimpleGcMemoryAllocator : MemoryAllocator
- {
- ///
- internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
- {
- return new BasicArrayBuffer(new T[length]);
- }
-
- internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options)
- {
- return new BasicByteBuffer(new byte[length]);
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
index 8048dd424e..bcabd4a163 100644
--- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs
@@ -8,6 +8,7 @@ using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters;
+using SixLabors.ImageSharp.Tests.Memory;
using SixLabors.Memory;
using Xunit;
@@ -290,7 +291,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
// no need to dispose when buffer is not array owner
- var source = new MemorySource(new BasicArrayBuffer(values), true);
+ var memory = new Memory(values);
+ var source = new MemorySource(memory);
buffers[i] = new Buffer2D(source, values.Length, 1);
}
return new JpegColorConverter.ComponentValues(buffers, 0);
diff --git a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs b/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs
deleted file mode 100644
index 89bb9d95f4..0000000000
--- a/tests/ImageSharp.Tests/Memory/ArrayPoolMemoryManagerTests.cs
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-// ReSharper disable InconsistentNaming
-
-using System.Buffers;
-
-using SixLabors.ImageSharp.PixelFormats;
-
-namespace SixLabors.ImageSharp.Tests.Memory
-{
- using System;
- using System.Linq;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
-
- using SixLabors.Memory;
-
- using Xunit;
-
- public class ArrayPoolMemoryManagerTests
- {
- private const int MaxPooledBufferSizeInBytes = 2048;
-
- private const int PoolSelectorThresholdInBytes = MaxPooledBufferSizeInBytes / 2;
-
- private MemoryAllocator MemoryAllocator { get; set; } = new ArrayPoolMemoryAllocator(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes);
-
- ///
- /// Rent a buffer -> return it -> re-rent -> verify if it's span points to the previous location
- ///
- private bool CheckIsRentingPooledBuffer(int length)
- where T : struct
- {
- IMemoryOwner buffer = this.MemoryAllocator.Allocate(length);
- ref T ptrToPrevPosition0 = ref buffer.GetReference();
- buffer.Dispose();
-
- buffer = this.MemoryAllocator.Allocate(length);
- bool sameBuffers = Unsafe.AreSame(ref ptrToPrevPosition0, ref buffer.GetReference());
- buffer.Dispose();
-
- return sameBuffers;
- }
-
- public class BufferTests : BufferTestSuite
- {
- public BufferTests()
- : base(new ArrayPoolMemoryAllocator(MaxPooledBufferSizeInBytes, PoolSelectorThresholdInBytes))
- {
- }
- }
-
- public class Constructor
- {
- [Fact]
- public void WhenBothParametersPassedByUser()
- {
- var mgr = new ArrayPoolMemoryAllocator(1111, 666);
- Assert.Equal(1111, mgr.MaxPoolSizeInBytes);
- Assert.Equal(666, mgr.PoolSelectorThresholdInBytes);
- }
-
- [Fact]
- public void WhenPassedOnly_MaxPooledBufferSizeInBytes_SmallerThresholdValueIsAutoCalculated()
- {
- var mgr = new ArrayPoolMemoryAllocator(5000);
- Assert.Equal(5000, mgr.MaxPoolSizeInBytes);
- Assert.True(mgr.PoolSelectorThresholdInBytes < mgr.MaxPoolSizeInBytes);
- }
-
- [Fact]
- public void When_PoolSelectorThresholdInBytes_IsGreaterThan_MaxPooledBufferSizeInBytes_ExceptionIsThrown()
- {
- Assert.ThrowsAny(() => { new ArrayPoolMemoryAllocator(100, 200); });
- }
- }
-
- [StructLayout(LayoutKind.Explicit, Size = MaxPooledBufferSizeInBytes / 5)]
- struct LargeStruct
- {
- }
-
- [Theory]
- [InlineData(32)]
- [InlineData(512)]
- [InlineData(MaxPooledBufferSizeInBytes - 1)]
- public void SmallBuffersArePooled_OfByte(int size)
- {
- Assert.True(this.CheckIsRentingPooledBuffer(size));
- }
-
-
- [Theory]
- [InlineData(128 * 1024 * 1024)]
- [InlineData(MaxPooledBufferSizeInBytes + 1)]
- public void LargeBuffersAreNotPooled_OfByte(int size)
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- Assert.False(this.CheckIsRentingPooledBuffer(size));
- }
-
- [Fact]
- public unsafe void SmallBuffersArePooled_OfBigValueType()
- {
- int count = MaxPooledBufferSizeInBytes / sizeof(LargeStruct) - 1;
-
- Assert.True(this.CheckIsRentingPooledBuffer(count));
- }
-
- [Fact]
- public unsafe void LaregeBuffersAreNotPooled_OfBigValueType()
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- int count = MaxPooledBufferSizeInBytes / sizeof(LargeStruct) + 1;
-
- Assert.False(this.CheckIsRentingPooledBuffer(count));
- }
-
- [Theory]
- [InlineData(AllocationOptions.None)]
- [InlineData(AllocationOptions.Clean)]
- public void CleaningRequests_AreControlledByAllocationParameter_Clean(AllocationOptions options)
- {
- using (IMemoryOwner firstAlloc = this.MemoryAllocator.Allocate(42))
- {
- firstAlloc.GetSpan().Fill(666);
- }
-
- using (IMemoryOwner secondAlloc = this.MemoryAllocator.Allocate(42, options))
- {
- int expected = options == AllocationOptions.Clean ? 0 : 666;
- Assert.Equal(expected, secondAlloc.GetSpan()[0]);
- }
- }
-
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void ReleaseRetainedResources_ReplacesInnerArrayPool(bool keepBufferAlive)
- {
- IMemoryOwner buffer = this.MemoryAllocator.Allocate(32);
- ref int ptrToPrev0 = ref MemoryMarshal.GetReference(buffer.GetSpan());
-
- if (!keepBufferAlive)
- {
- buffer.Dispose();
- }
-
- this.MemoryAllocator.ReleaseRetainedResources();
-
- buffer = this.MemoryAllocator.Allocate(32);
-
- Assert.False(Unsafe.AreSame(ref ptrToPrev0, ref buffer.GetReference()));
- }
-
- [Fact]
- public void ReleaseRetainedResources_DisposingPreviouslyAllocatedBuffer_IsAllowed()
- {
- IMemoryOwner buffer = this.MemoryAllocator.Allocate(32);
- this.MemoryAllocator.ReleaseRetainedResources();
- buffer.Dispose();
- }
-
- [Fact]
- public void AllocationOverLargeArrayThreshold_UsesDifferentPool()
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- int arrayLengthThreshold = PoolSelectorThresholdInBytes / sizeof(int);
-
- IMemoryOwner small = this.MemoryAllocator.Allocate(arrayLengthThreshold - 1);
- ref int ptr2Small = ref small.GetReference();
- small.Dispose();
-
- IMemoryOwner large = this.MemoryAllocator.Allocate(arrayLengthThreshold + 1);
-
- Assert.False(Unsafe.AreSame(ref ptr2Small, ref large.GetReference()));
- }
-
- [Fact]
- public void CreateWithAggressivePooling()
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateWithAggressivePooling();
-
- Assert.True(this.CheckIsRentingPooledBuffer(4096 * 4096));
- }
-
- [Fact]
- public void CreateDefault()
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateDefault();
-
- Assert.False(this.CheckIsRentingPooledBuffer(2 * 4096 * 4096));
- Assert.True(this.CheckIsRentingPooledBuffer(2048 * 2048));
- }
-
- [Fact]
- public void CreateWithModeratePooling()
- {
- if (!TestEnvironment.Is64BitProcess)
- {
- // can lead to OutOfMemoryException
- return;
- }
-
- this.MemoryAllocator = ArrayPoolMemoryAllocator.CreateWithModeratePooling();
-
- Assert.False(this.CheckIsRentingPooledBuffer(2048 * 2048));
- Assert.True(this.CheckIsRentingPooledBuffer(1024 * 16));
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs b/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs
deleted file mode 100644
index e57c13164a..0000000000
--- a/tests/ImageSharp.Tests/Memory/BufferTestSuite.cs
+++ /dev/null
@@ -1,320 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using SixLabors.Memory;
-using Xunit;
-// ReSharper disable InconsistentNaming
-
-namespace SixLabors.ImageSharp.Tests.Memory
-{
- using System.Buffers;
-
- ///
- /// Inherit this class to test an implementation (provided by ).
- ///
- public abstract class BufferTestSuite
- {
- protected BufferTestSuite(MemoryAllocator memoryAllocator)
- {
- this.MemoryAllocator = memoryAllocator;
- }
-
- protected MemoryAllocator MemoryAllocator { get; }
-
- public struct CustomStruct : IEquatable
- {
- public long A;
-
- public byte B;
-
- public float C;
-
- public CustomStruct(long a, byte b, float c)
- {
- this.A = a;
- this.B = b;
- this.C = c;
- }
-
- public bool Equals(CustomStruct other)
- {
- return this.A == other.A && this.B == other.B && this.C.Equals(other.C);
- }
-
- public override bool Equals(object obj)
- {
- return obj is CustomStruct other && this.Equals(other);
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hashCode = this.A.GetHashCode();
- hashCode = (hashCode * 397) ^ this.B.GetHashCode();
- hashCode = (hashCode * 397) ^ this.C.GetHashCode();
- return hashCode;
- }
- }
- }
-
- public static readonly TheoryData LenthValues = new TheoryData { 0, 1, 7, 1023, 1024 };
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void HasCorrectLength_byte(int desiredLength)
- {
- this.TestHasCorrectLength(desiredLength);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void HasCorrectLength_float(int desiredLength)
- {
- this.TestHasCorrectLength(desiredLength);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void HasCorrectLength_CustomStruct(int desiredLength)
- {
- this.TestHasCorrectLength(desiredLength);
- }
-
- private void TestHasCorrectLength(int desiredLength)
- where T : struct
- {
- using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(desiredLength))
- {
- Assert.Equal(desiredLength, buffer.GetSpan().Length);
- }
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void CanAllocateCleanBuffer_byte(int desiredLength)
- {
- this.TestCanAllocateCleanBuffer(desiredLength, false);
- this.TestCanAllocateCleanBuffer(desiredLength, true);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void CanAllocateCleanBuffer_double(int desiredLength)
- {
- this.TestCanAllocateCleanBuffer(desiredLength);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void CanAllocateCleanBuffer_CustomStruct(int desiredLength)
- {
- this.TestCanAllocateCleanBuffer(desiredLength);
- }
-
- private IMemoryOwner Allocate(int desiredLength, AllocationOptions options, bool managedByteBuffer)
- where T : struct
- {
- if (managedByteBuffer)
- {
- if (!(this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength, options) is IMemoryOwner buffer))
- {
- throw new InvalidOperationException("typeof(T) != typeof(byte)");
- }
-
- return buffer;
- }
-
- return this.MemoryAllocator.Allocate(desiredLength, options);
- }
-
- private void TestCanAllocateCleanBuffer(int desiredLength, bool testManagedByteBuffer = false)
- where T : struct, IEquatable
- {
- ReadOnlySpan expected = new T[desiredLength];
-
- for (int i = 0; i < 10; i++)
- {
- using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.Clean, testManagedByteBuffer))
- {
- Assert.True(buffer.GetSpan().SequenceEqual(expected));
- }
- }
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void SpanPropertyIsAlwaysTheSame_int(int desiredLength)
- {
- this.TestSpanPropertyIsAlwaysTheSame(desiredLength);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void SpanPropertyIsAlwaysTheSame_byte(int desiredLength)
- {
- this.TestSpanPropertyIsAlwaysTheSame(desiredLength, false);
- this.TestSpanPropertyIsAlwaysTheSame(desiredLength, true);
- }
-
- private void TestSpanPropertyIsAlwaysTheSame(int desiredLength, bool testManagedByteBuffer = false)
- where T : struct
- {
- using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
- {
- ref T a = ref MemoryMarshal.GetReference(buffer.GetSpan());
- ref T b = ref MemoryMarshal.GetReference(buffer.GetSpan());
- ref T c = ref MemoryMarshal.GetReference(buffer.GetSpan());
-
- Assert.True(Unsafe.AreSame(ref a, ref b));
- Assert.True(Unsafe.AreSame(ref b, ref c));
- }
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void WriteAndReadElements_float(int desiredLength)
- {
- this.TestWriteAndReadElements(desiredLength, x => x * 1.2f);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void WriteAndReadElements_byte(int desiredLength)
- {
- this.TestWriteAndReadElements(desiredLength, x => (byte)(x+1), false);
- this.TestWriteAndReadElements(desiredLength, x => (byte)(x + 1), true);
- }
-
- private void TestWriteAndReadElements(int desiredLength, Func getExpectedValue, bool testManagedByteBuffer = false)
- where T : struct
- {
- using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
- {
- T[] expectedVals = new T[buffer.Length()];
-
- for (int i = 0; i < buffer.Length(); i++)
- {
- Span span = buffer.GetSpan();
- expectedVals[i] = getExpectedValue(i);
- span[i] = expectedVals[i];
- }
-
- for (int i = 0; i < buffer.Length(); i++)
- {
- Span span = buffer.GetSpan();
- Assert.Equal(expectedVals[i], span[i]);
- }
- }
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void IndexingSpan_WhenOutOfRange_Throws_byte(int desiredLength)
- {
- this.TestIndexOutOfRangeShouldThrow(desiredLength, false);
- this.TestIndexOutOfRangeShouldThrow(desiredLength, true);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void IndexingSpan_WhenOutOfRange_Throws_long(int desiredLength)
- {
- this.TestIndexOutOfRangeShouldThrow(desiredLength);
- }
-
- [Theory]
- [MemberData(nameof(LenthValues))]
- public void IndexingSpan_WhenOutOfRange_Throws_CustomStruct(int desiredLength)
- {
- this.TestIndexOutOfRangeShouldThrow(desiredLength);
- }
-
- private T TestIndexOutOfRangeShouldThrow(int desiredLength, bool testManagedByteBuffer = false)
- where T : struct, IEquatable
- {
- var dummy = default(T);
-
- using (IMemoryOwner buffer = this.Allocate(desiredLength, AllocationOptions.None, testManagedByteBuffer))
- {
- Assert.ThrowsAny(
- () =>
- {
- Span span = buffer.GetSpan();
- dummy = span[desiredLength];
- });
-
- Assert.ThrowsAny(
- () =>
- {
- Span span = buffer.GetSpan();
- dummy = span[desiredLength + 1];
- });
-
- Assert.ThrowsAny(
- () =>
- {
- Span span = buffer.GetSpan();
- dummy = span[desiredLength + 42];
- });
- }
-
- return dummy;
- }
-
- [Theory]
- [InlineData(1)]
- [InlineData(7)]
- [InlineData(1024)]
- [InlineData(6666)]
- public void ManagedByteBuffer_ArrayIsCorrect(int desiredLength)
- {
- using (IManagedByteBuffer buffer = this.MemoryAllocator.AllocateManagedByteBuffer(desiredLength))
- {
- ref byte array0 = ref buffer.Array[0];
- ref byte span0 = ref buffer.GetReference();
-
- Assert.True(Unsafe.AreSame(ref span0, ref array0));
- Assert.True(buffer.Array.Length >= buffer.GetSpan().Length);
- }
- }
-
- [Fact]
- public void GetMemory_ReturnsValidMemory()
- {
- using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42))
- {
- Span span0 = buffer.GetSpan();
- span0[10].A = 30;
- Memory memory = buffer.Memory;
-
- Assert.Equal(42, memory.Length);
- Span span1 = memory.Span;
-
- Assert.Equal(42, span1.Length);
- Assert.Equal(30, span1[10].A);
- }
- }
-
- [Fact]
- public unsafe void GetMemory_ResultIsPinnable()
- {
- using (IMemoryOwner buffer = this.MemoryAllocator.Allocate(42))
- {
- Span span0 = buffer.GetSpan();
- span0[10] = 30;
-
- Memory memory = buffer.Memory;
-
- using (MemoryHandle h = memory.Pin())
- {
- int* ptr = (int*) h.Pointer;
- Assert.Equal(30, ptr[10]);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Memory/SimpleGcMemoryManagerTests.cs b/tests/ImageSharp.Tests/Memory/SimpleGcMemoryManagerTests.cs
deleted file mode 100644
index d04336690c..0000000000
--- a/tests/ImageSharp.Tests/Memory/SimpleGcMemoryManagerTests.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace SixLabors.ImageSharp.Tests.Memory
-{
- using SixLabors.Memory;
-
- public class SimpleGcMemoryManagerTests
- {
- public class BufferTests : BufferTestSuite
- {
- public BufferTests()
- : base(new SimpleGcMemoryAllocator())
- {
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs b/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
deleted file mode 100644
index 396fb4ca99..0000000000
--- a/tests/ImageSharp.Tests/Memory/SpanUtilityTests.cs
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-// ReSharper disable InconsistentNaming
-// ReSharper disable AccessToStaticMemberViaDerivedType
-namespace SixLabors.ImageSharp.Tests.Memory
-{
- using System;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using Xunit;
-
- public unsafe class SpanUtilityTests
- {
- // ReSharper disable once ClassNeverInstantiated.Local
- private class Assert : Xunit.Assert
- {
- public static void SameRefs(ref T1 a, ref T2 b)
- {
- ref T1 bb = ref Unsafe.As(ref b);
-
- Assert.True(Unsafe.AreSame(ref a, ref bb), "References are not same!");
- }
- }
-
- public class SpanHelper_Copy
- {
- private static void AssertNotDefault(T[] data, int idx)
- where T : struct
- {
- Assert.NotEqual(default, data[idx]);
- }
-
- private static byte[] CreateTestBytes(int count)
- {
- byte[] result = new byte[count];
- for (int i = 0; i < result.Length; i++)
- {
- result[i] = (byte)((i % 200) + 1);
- }
- return result;
- }
-
- private static int[] CreateTestInts(int count)
- {
- int[] result = new int[count];
- for (int i = 0; i < result.Length; i++)
- {
- result[i] = i + 1;
- }
- return result;
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void GenericToOwnType(int count)
- {
- TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
- var dest = new TestStructs.Foo[count + 5];
-
- var apSource = new Span(source, 1, source.Length - 1);
- var apDest = new Span(dest, 1, dest.Length - 1);
-
- apSource.Slice(0, count - 1).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
- AssertNotDefault(dest, 1);
-
- Assert.NotEqual(source[0], dest[0]);
- Assert.Equal(source[1], dest[1]);
- Assert.Equal(source[2], dest[2]);
- Assert.Equal(source[count - 1], dest[count - 1]);
- Assert.NotEqual(source[count], dest[count]);
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void GenericToOwnType_Aligned(int count)
- {
- TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
- var dest = new TestStructs.AlignedFoo[count + 5];
-
- var apSource = new Span(source, 1, source.Length - 1);
- var apDest = new Span(dest, 1, dest.Length - 1);
-
- apSource.Slice(0, count - 1).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
- AssertNotDefault(dest, 1);
-
- Assert.NotEqual(source[0], dest[0]);
- Assert.Equal(source[1], dest[1]);
- Assert.Equal(source[2], dest[2]);
- Assert.Equal(source[count - 1], dest[count - 1]);
- Assert.NotEqual(source[count], dest[count]);
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void IntToInt(int count)
- {
- int[] source = CreateTestInts(count + 2);
- int[] dest = new int[count + 5];
-
- var apSource = new Span(source, 1, source.Length - 1);
- var apDest = new Span(dest, 1, dest.Length - 1);
-
- apSource.Slice(0, count - 1).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
- AssertNotDefault(dest, 1);
-
- Assert.NotEqual(source[0], dest[0]);
- Assert.Equal(source[1], dest[1]);
- Assert.Equal(source[2], dest[2]);
- Assert.Equal(source[count - 1], dest[count - 1]);
- Assert.NotEqual(source[count], dest[count]);
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void GenericToBytes(int count)
- {
- int destCount = count * sizeof(TestStructs.Foo);
- TestStructs.Foo[] source = TestStructs.Foo.CreateArray(count + 2);
- byte[] dest = new byte[destCount + sizeof(TestStructs.Foo) * 2];
-
- var apSource = new Span(source, 1, source.Length - 1);
- var apDest = new Span(dest, sizeof(TestStructs.Foo), dest.Length - sizeof(TestStructs.Foo));
-
- MemoryMarshal.AsBytes(apSource).Slice(0, (count - 1) * sizeof(TestStructs.Foo)).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
-
- Assert.False((bool)ElementsAreEqual(source, dest, 0));
- Assert.True((bool)ElementsAreEqual(source, dest, 1));
- Assert.True((bool)ElementsAreEqual(source, dest, 2));
- Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
- Assert.False((bool)ElementsAreEqual(source, dest, count));
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void GenericToBytes_Aligned(int count)
- {
- int destCount = count * sizeof(TestStructs.Foo);
- TestStructs.AlignedFoo[] source = TestStructs.AlignedFoo.CreateArray(count + 2);
- byte[] dest = new byte[destCount + sizeof(TestStructs.AlignedFoo) * 2];
-
- var apSource = new Span(source, 1, source.Length - 1);
- var apDest = new Span(dest, sizeof(TestStructs.AlignedFoo), dest.Length - sizeof(TestStructs.AlignedFoo));
-
- MemoryMarshal.AsBytes(apSource).Slice(0, (count - 1) * sizeof(TestStructs.AlignedFoo)).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
-
- Assert.False((bool)ElementsAreEqual(source, dest, 0));
- Assert.True((bool)ElementsAreEqual(source, dest, 1));
- Assert.True((bool)ElementsAreEqual(source, dest, 2));
- Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
- Assert.False((bool)ElementsAreEqual(source, dest, count));
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void IntToBytes(int count)
- {
- int destCount = count * sizeof(int);
- int[] source = CreateTestInts(count + 2);
- byte[] dest = new byte[destCount + sizeof(int) + 1];
-
- var apSource = new Span(source);
- var apDest = new Span(dest);
-
- MemoryMarshal.AsBytes(apSource).Slice(0, count * sizeof(int)).CopyTo(apDest);
-
- AssertNotDefault(source, 1);
-
- Assert.True((bool)ElementsAreEqual(source, dest, 0));
- Assert.True((bool)ElementsAreEqual(source, dest, count - 1));
- Assert.False((bool)ElementsAreEqual(source, dest, count));
- }
-
- [Theory]
- [InlineData(4)]
- [InlineData(1500)]
- public void BytesToGeneric(int count)
- {
- int srcCount = count * sizeof(TestStructs.Foo);
- byte[] source = CreateTestBytes(srcCount);
- var dest = new TestStructs.Foo[count + 2];
-
- var apSource = new Span(source);
- var apDest = new Span(dest);
-
- apSource.Slice(0, count * sizeof(TestStructs.Foo)).CopyTo(MemoryMarshal.AsBytes(apDest));
-
- AssertNotDefault(source, sizeof(TestStructs.Foo) + 1);
- AssertNotDefault(dest, 1);
-
- Assert.True((bool)ElementsAreEqual(dest, source, 0));
- Assert.True((bool)ElementsAreEqual(dest, source, 1));
- Assert.True((bool)ElementsAreEqual(dest, source, count - 1));
-
- // Difference is 2.4380727671472639E-289
- // 32 bit doesn't compare accuarately enough and is blocking our PR's
- // TODO: Refactor a better test.
- if (Environment.Is64BitProcess)
- {
- Assert.False((bool)ElementsAreEqual(dest, source, count));
- }
- }
-
- internal static bool ElementsAreEqual(TestStructs.Foo[] array, byte[] rawArray, int index)
- {
- fixed (TestStructs.Foo* pArray = array)
- fixed (byte* pRaw = rawArray)
- {
- var pCasted = (TestStructs.Foo*)pRaw;
-
- TestStructs.Foo val1 = pArray[index];
- TestStructs.Foo val2 = pCasted[index];
-
- return val1.Equals(val2);
- }
- }
-
- internal static bool ElementsAreEqual(TestStructs.AlignedFoo[] array, byte[] rawArray, int index)
- {
- fixed (TestStructs.AlignedFoo* pArray = array)
- fixed (byte* pRaw = rawArray)
- {
- var pCasted = (TestStructs.AlignedFoo*)pRaw;
-
- TestStructs.AlignedFoo val1 = pArray[index];
- TestStructs.AlignedFoo val2 = pCasted[index];
-
- return val1.Equals(val2);
- }
- }
-
- internal static bool ElementsAreEqual(int[] array, byte[] rawArray, int index)
- {
- fixed (int* pArray = array)
- fixed (byte* pRaw = rawArray)
- {
- int* pCasted = (int*)pRaw;
-
- int val1 = pArray[index];
- int val2 = pCasted[index];
-
- return val1.Equals(val2);
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs
index a580fc7ad6..dc755e6827 100644
--- a/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs
+++ b/tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs
@@ -18,14 +18,14 @@ namespace SixLabors.ImageSharp.Tests.Memory
///
public byte DirtyValue { get; }
- internal override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
+ public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
{
T[] array = this.AllocateArray(length, options);
return new BasicArrayBuffer(array, length);
}
- internal override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
+ public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
byte[] array = this.AllocateArray(length, options);
return new ManagedByteBuffer(array);
@@ -45,6 +45,70 @@ namespace SixLabors.ImageSharp.Tests.Memory
return array;
}
+ ///
+ /// Wraps an array as an instance.
+ ///
+ private class BasicArrayBuffer : MemoryManager
+ where T : struct
+ {
+ private GCHandle pinHandle;
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The array
+ /// The length of the buffer
+ public BasicArrayBuffer(T[] array, int length)
+ {
+ DebugGuard.MustBeLessThanOrEqualTo(length, array.Length, nameof(length));
+ this.Array = array;
+ this.Length = length;
+ }
+
+ ///
+ /// Initializes a new instance of the class
+ ///
+ /// The array
+ public BasicArrayBuffer(T[] array)
+ : this(array, array.Length)
+ {
+ }
+
+ ///
+ /// Gets the array
+ ///
+ public T[] Array { get; }
+
+ ///
+ /// Gets the length
+ ///
+ public int Length { get; }
+
+ ///
+ public override Span GetSpan() => this.Array.AsSpan(0, this.Length);
+
+ public override unsafe MemoryHandle Pin(int elementIndex = 0)
+ {
+ if (!this.pinHandle.IsAllocated)
+ {
+ this.pinHandle = GCHandle.Alloc(this.Array, GCHandleType.Pinned);
+ }
+
+ void* ptr = (void*)this.pinHandle.AddrOfPinnedObject();
+ return new MemoryHandle(ptr, this.pinHandle);
+ }
+
+ public override void Unpin()
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ }
+ }
+
private class ManagedByteBuffer : BasicArrayBuffer, IManagedByteBuffer
{
public ManagedByteBuffer(byte[] array)