mirror of
https://github.com/chylex/.NET-Community-Toolkit.git
synced 2025-04-13 20:15:45 +02:00
Merge branch 'master' into bugfix/task-result-converter
This commit is contained in:
commit
16f6c4687b
Microsoft.Toolkit.HighPerformance
UnitTests/UnitTests.HighPerformance.Shared
@ -78,9 +78,9 @@
|
||||
|
||||
<!-- NETCORE_RUNTIME: to avoid issues with APIs that assume a specific memory layout, we define a
|
||||
.NET Core runtime constant to indicate the either .NET Core 2.1 or .NET Core 3.1. These are
|
||||
runtimes with the same overall memory layout for objects (in particular: strings, SZ arrays
|
||||
runtimes with the same overall memory layout for objects (in particular: strings, SZ arrays,
|
||||
and 2D arrays). We can use this constant to make sure that APIs that are exclusively available
|
||||
for .NET Standard targets do not make any assumtpion of any internals of the runtime being
|
||||
for .NET Standard targets do not make any assumption of any internals of the runtime being
|
||||
actually used by the consumers. -->
|
||||
<DefineConstants>NETSTANDARD2_1_OR_GREATER;SPAN_RUNTIME_SUPPORT;NETCORE_RUNTIME</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
@ -0,0 +1,82 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace UnitTests.HighPerformance.Shared.Buffers.Internals
|
||||
{
|
||||
/// <summary>
|
||||
/// An owner for a buffer of an unmanaged type, recycling <see cref="byte"/> arrays to save memory.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of items to store in the rented buffers.</typeparam>
|
||||
internal sealed unsafe class UnmanagedSpanOwner<T> : MemoryManager<T>
|
||||
where T : unmanaged
|
||||
{
|
||||
/// <summary>
|
||||
/// The size of the current instance
|
||||
/// </summary>
|
||||
private readonly int length;
|
||||
|
||||
/// <summary>
|
||||
/// The pointer to the underlying <see cref="byte"/> array.
|
||||
/// </summary>
|
||||
private IntPtr ptr;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UnmanagedSpanOwner{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="size">The size of the buffer to rent.</param>
|
||||
public UnmanagedSpanOwner(int size)
|
||||
{
|
||||
this.ptr = Marshal.AllocHGlobal(size * Unsafe.SizeOf<T>());
|
||||
this.length = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the buffer in use.
|
||||
/// </summary>
|
||||
public int Length => this.length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a pointer to the start of the buffer in use.
|
||||
/// </summary>
|
||||
public T* Ptr => (T*)this.ptr;
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
IntPtr ptr = this.ptr;
|
||||
|
||||
if (ptr == IntPtr.Zero)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
this.ptr = IntPtr.Zero;
|
||||
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override Span<T> GetSpan()
|
||||
{
|
||||
return new Span<T>((void*)this.ptr, this.length);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override MemoryHandle Pin(int elementIndex = 0)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Unpin()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,9 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Toolkit.HighPerformance.Extensions;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace UnitTests.HighPerformance.Extensions
|
||||
{
|
||||
@ -168,15 +171,15 @@ public void Test_ReadOnlySpanExtensions_FilledCount64()
|
||||
/// <typeparam name="T">The type to test.</typeparam>
|
||||
/// <param name="value">The target value to look for.</param>
|
||||
/// <param name="provider">The function to use to create random data.</param>
|
||||
private static void TestForType<T>(T value, Func<int, T, T[]> provider)
|
||||
private static void TestForType<T>(T value, Func<int, T, UnmanagedSpanOwner<T>> provider)
|
||||
where T : unmanaged, IEquatable<T>
|
||||
{
|
||||
foreach (var count in TestCounts)
|
||||
{
|
||||
T[] data = provider(count, value);
|
||||
using UnmanagedSpanOwner<T> data = provider(count, value);
|
||||
|
||||
int result = data.Count(value);
|
||||
int expected = CountWithForeach(data, value);
|
||||
int result = data.GetSpan().Count(value);
|
||||
int expected = CountWithForeach(data.GetSpan(), value);
|
||||
|
||||
Assert.AreEqual(result, expected, $"Failed {typeof(T)} test with count {count}: got {result} instead of {expected}");
|
||||
}
|
||||
@ -214,14 +217,14 @@ private static int CountWithForeach<T>(ReadOnlySpan<T> span, T value)
|
||||
/// <param name="value">The value to look for.</param>
|
||||
/// <returns>An array of random <typeparamref name="T"/> elements.</returns>
|
||||
[Pure]
|
||||
private static T[] CreateRandomData<T>(int count, T value)
|
||||
private static UnmanagedSpanOwner<T> CreateRandomData<T>(int count, T value)
|
||||
where T : unmanaged
|
||||
{
|
||||
var random = new Random(count);
|
||||
|
||||
T[] data = new T[count];
|
||||
UnmanagedSpanOwner<T> data = new UnmanagedSpanOwner<T>(count);
|
||||
|
||||
foreach (ref byte n in MemoryMarshal.AsBytes(data.AsSpan()))
|
||||
foreach (ref byte n in MemoryMarshal.AsBytes(data.GetSpan()))
|
||||
{
|
||||
n = (byte)random.Next(0, byte.MaxValue);
|
||||
}
|
||||
@ -229,9 +232,11 @@ private static T[] CreateRandomData<T>(int count, T value)
|
||||
// Fill at least 20% of the items with a matching value
|
||||
int minimum = count / 20;
|
||||
|
||||
Span<T> span = data.GetSpan();
|
||||
|
||||
for (int i = 0; i < minimum; i++)
|
||||
{
|
||||
data[random.Next(0, count)] = value;
|
||||
span[random.Next(0, count)] = value;
|
||||
}
|
||||
|
||||
return data;
|
||||
@ -245,12 +250,12 @@ private static T[] CreateRandomData<T>(int count, T value)
|
||||
/// <param name="value">The value to use to populate the array.</param>
|
||||
/// <returns>An array of <typeparamref name="T"/> elements.</returns>
|
||||
[Pure]
|
||||
private static T[] CreateFilledData<T>(int count, T value)
|
||||
private static UnmanagedSpanOwner<T> CreateFilledData<T>(int count, T value)
|
||||
where T : unmanaged
|
||||
{
|
||||
T[] data = new T[count];
|
||||
UnmanagedSpanOwner<T> data = new UnmanagedSpanOwner<T>(count);
|
||||
|
||||
data.AsSpan().Fill(value);
|
||||
data.GetSpan().Fill(value);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
@ -18,7 +18,9 @@ public partial class Test_ReadOnlySpanExtensions
|
||||
[TestMethod]
|
||||
public void Test_ReadOnlySpanExtensions_DangerousGetReference()
|
||||
{
|
||||
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
|
||||
using var owner = CreateRandomData<int>(12, default);
|
||||
|
||||
ReadOnlySpan<int> data = owner.GetSpan();
|
||||
|
||||
ref int r0 = ref data.DangerousGetReference();
|
||||
ref int r1 = ref Unsafe.AsRef(data[0]);
|
||||
@ -30,7 +32,9 @@ public void Test_ReadOnlySpanExtensions_DangerousGetReference()
|
||||
[TestMethod]
|
||||
public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Zero()
|
||||
{
|
||||
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
|
||||
using var owner = CreateRandomData<int>(12, default);
|
||||
|
||||
ReadOnlySpan<int> data = owner.GetSpan();
|
||||
|
||||
ref int r0 = ref data.DangerousGetReference();
|
||||
ref int r1 = ref data.DangerousGetReferenceAt(0);
|
||||
@ -42,7 +46,9 @@ public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Zero()
|
||||
[TestMethod]
|
||||
public void Test_ReadOnlySpanExtensions_DangerousGetReferenceAt_Index()
|
||||
{
|
||||
ReadOnlySpan<int> data = CreateRandomData<int>(12, default).AsSpan();
|
||||
using var owner = CreateRandomData<int>(12, default);
|
||||
|
||||
ReadOnlySpan<int> data = owner.GetSpan();
|
||||
|
||||
ref int r0 = ref data.DangerousGetReferenceAt(5);
|
||||
ref int r1 = ref Unsafe.AsRef(data[5]);
|
||||
|
@ -8,6 +8,7 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Toolkit.HighPerformance.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
namespace UnitTests.HighPerformance.Helpers
|
||||
{
|
||||
@ -67,19 +68,23 @@ public void Test_HashCodeOfT_VectorUnsupportedTypes_TestRepeat()
|
||||
[TestMethod]
|
||||
public void Test_HashCodeOfT_ManagedType_TestRepeat()
|
||||
{
|
||||
var localTestCounts = TestCounts.Slice(0, 8);
|
||||
|
||||
// Only rent a single array of the maximum necessary size, to save space
|
||||
string[] data = new string[localTestCounts[localTestCounts.Length - 1]];
|
||||
|
||||
var random = new Random();
|
||||
|
||||
foreach (var count in TestCounts.Slice(0, 8))
|
||||
foreach (ref string text in data.AsSpan())
|
||||
{
|
||||
string[] data = new string[count];
|
||||
text = random.NextDouble().ToString("E");
|
||||
}
|
||||
|
||||
foreach (ref string text in data.AsSpan())
|
||||
{
|
||||
text = random.NextDouble().ToString("E");
|
||||
}
|
||||
foreach (var count in localTestCounts)
|
||||
{
|
||||
Span<string> iterationData = data.AsSpan().Slice(0, count);
|
||||
|
||||
int hash1 = HashCode<string>.Combine(data);
|
||||
int hash2 = HashCode<string>.Combine(data);
|
||||
int hash1 = HashCode<string>.Combine(iterationData);
|
||||
int hash2 = HashCode<string>.Combine(iterationData);
|
||||
|
||||
Assert.AreEqual(hash1, hash2, $"Failed {typeof(string)} test with count {count}: got {hash1} and then {hash2}");
|
||||
}
|
||||
@ -95,10 +100,10 @@ private static void TestForType<T>()
|
||||
{
|
||||
foreach (var count in TestCounts)
|
||||
{
|
||||
T[] data = CreateRandomData<T>(count);
|
||||
using UnmanagedSpanOwner<T> data = CreateRandomData<T>(count);
|
||||
|
||||
int hash1 = HashCode<T>.Combine(data);
|
||||
int hash2 = HashCode<T>.Combine(data);
|
||||
int hash1 = HashCode<T>.Combine(data.GetSpan());
|
||||
int hash2 = HashCode<T>.Combine(data.GetSpan());
|
||||
|
||||
Assert.AreEqual(hash1, hash2, $"Failed {typeof(T)} test with count {count}: got {hash1} and then {hash2}");
|
||||
}
|
||||
@ -111,14 +116,14 @@ private static void TestForType<T>()
|
||||
/// <param name="count">The number of array items to create.</param>
|
||||
/// <returns>An array of random <typeparamref name="T"/> elements.</returns>
|
||||
[Pure]
|
||||
private static T[] CreateRandomData<T>(int count)
|
||||
private static UnmanagedSpanOwner<T> CreateRandomData<T>(int count)
|
||||
where T : unmanaged
|
||||
{
|
||||
var random = new Random(count);
|
||||
|
||||
T[] data = new T[count];
|
||||
UnmanagedSpanOwner<T> data = new UnmanagedSpanOwner<T>(count);
|
||||
|
||||
foreach (ref byte n in MemoryMarshal.AsBytes(data.AsSpan()))
|
||||
foreach (ref byte n in MemoryMarshal.AsBytes(data.GetSpan()))
|
||||
{
|
||||
n = (byte)random.Next(0, byte.MaxValue);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
using Microsoft.Toolkit.HighPerformance.Extensions;
|
||||
using Microsoft.Toolkit.HighPerformance.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
namespace UnitTests.HighPerformance.Helpers
|
||||
{
|
||||
@ -19,15 +20,17 @@ public partial class Test_ParallelHelper
|
||||
|
||||
[TestCategory("ParallelHelper")]
|
||||
[TestMethod]
|
||||
public void Test_ParallelHelper_ForWithIndices()
|
||||
public unsafe void Test_ParallelHelper_ForWithIndices()
|
||||
{
|
||||
foreach (int count in TestForCounts)
|
||||
{
|
||||
int[] data = new int[count];
|
||||
using UnmanagedSpanOwner<int> data = new UnmanagedSpanOwner<int>(count);
|
||||
|
||||
ParallelHelper.For(0, data.Length, new Assigner(data));
|
||||
data.GetSpan().Clear();
|
||||
|
||||
foreach (var item in data.Enumerate())
|
||||
ParallelHelper.For(0, data.Length, new Assigner(data.Length, data.Ptr));
|
||||
|
||||
foreach (var item in data.GetSpan().Enumerate())
|
||||
{
|
||||
if (item.Index != item.Value)
|
||||
{
|
||||
@ -56,15 +59,17 @@ public void Test_ParallelHelper_ForInvalidRange_RangeAll()
|
||||
|
||||
[TestCategory("ParallelHelper")]
|
||||
[TestMethod]
|
||||
public void Test_ParallelHelper_ForWithRanges()
|
||||
public unsafe void Test_ParallelHelper_ForWithRanges()
|
||||
{
|
||||
foreach (int count in TestForCounts)
|
||||
{
|
||||
int[] data = new int[count];
|
||||
using UnmanagedSpanOwner<int> data = new UnmanagedSpanOwner<int>(count);
|
||||
|
||||
ParallelHelper.For(..data.Length, new Assigner(data));
|
||||
data.GetSpan().Clear();
|
||||
|
||||
foreach (var item in data.Enumerate())
|
||||
ParallelHelper.For(..data.Length, new Assigner(data.Length, data.Ptr));
|
||||
|
||||
foreach (var item in data.GetSpan().Enumerate())
|
||||
{
|
||||
if (item.Index != item.Value)
|
||||
{
|
||||
@ -78,21 +83,31 @@ public void Test_ParallelHelper_ForWithRanges()
|
||||
/// <summary>
|
||||
/// A type implementing <see cref="IAction"/> to initialize an array
|
||||
/// </summary>
|
||||
private readonly struct Assigner : IAction
|
||||
private readonly unsafe struct Assigner : IAction
|
||||
{
|
||||
private readonly int[] array;
|
||||
private readonly int length;
|
||||
private readonly int* ptr;
|
||||
|
||||
public Assigner(int[] array) => this.array = array;
|
||||
public Assigner(int length, int* ptr)
|
||||
{
|
||||
this.length = length;
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Invoke(int i)
|
||||
{
|
||||
if (this.array[i] != 0)
|
||||
if ((uint)i >= (uint)this.length)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid target position {i}, was {this.array[i]} instead of 0");
|
||||
throw new IndexOutOfRangeException($"The target position was out of range, was {i} and should've been in [0, {this.length})");
|
||||
}
|
||||
|
||||
this.array[i] = i;
|
||||
if (this.ptr[i] != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid target position {i}, was {this.ptr[i]} instead of 0");
|
||||
}
|
||||
|
||||
this.ptr[i] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
using System.Drawing;
|
||||
using Microsoft.Toolkit.HighPerformance.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
namespace UnitTests.HighPerformance.Helpers
|
||||
{
|
||||
@ -27,21 +28,23 @@ public partial class Test_ParallelHelper
|
||||
|
||||
[TestCategory("ParallelHelper")]
|
||||
[TestMethod]
|
||||
public void Test_ParallelHelper_For2DWithIndices()
|
||||
public unsafe void Test_ParallelHelper_For2DWithIndices()
|
||||
{
|
||||
foreach (var size in TestFor2DSizes)
|
||||
{
|
||||
int[,] data = new int[size.Height, size.Width];
|
||||
using UnmanagedSpanOwner<int> data = new UnmanagedSpanOwner<int>(size.Height * size.Width);
|
||||
|
||||
ParallelHelper.For2D(0, size.Height, 0, size.Width, new Assigner2D(data));
|
||||
data.GetSpan().Clear();
|
||||
|
||||
ParallelHelper.For2D(0, size.Height, 0, size.Width, new Assigner2D(size.Height, size.Width, data.Ptr));
|
||||
|
||||
for (int i = 0; i < size.Height; i++)
|
||||
{
|
||||
for (int j = 0; j < size.Width; j++)
|
||||
{
|
||||
if (data[i, j] != unchecked(i * 397 ^ j))
|
||||
if (data.Ptr[(i * size.Width) + j] != unchecked(i * 397 ^ j))
|
||||
{
|
||||
Assert.Fail($"Invalid item at position [{i},{j}], value was {data[i, j]} instead of {unchecked(i * 397 ^ j)}");
|
||||
Assert.Fail($"Invalid item at position [{i},{j}], value was {data.Ptr[(i * size.Width) + j]} instead of {unchecked(i * 397 ^ j)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,21 +70,23 @@ public void Test_ParallelHelper_For2DInvalidRange_RangeAll()
|
||||
|
||||
[TestCategory("ParallelHelper")]
|
||||
[TestMethod]
|
||||
public void Test_ParallelHelper_For2DWithRanges()
|
||||
public unsafe void Test_ParallelHelper_For2DWithRanges()
|
||||
{
|
||||
foreach (var size in TestFor2DSizes)
|
||||
{
|
||||
int[,] data = new int[size.Height, size.Width];
|
||||
using UnmanagedSpanOwner<int> data = new UnmanagedSpanOwner<int>(size.Height * size.Width);
|
||||
|
||||
ParallelHelper.For2D(..size.Height, ..size.Width, new Assigner2D(data));
|
||||
data.GetSpan().Clear();
|
||||
|
||||
ParallelHelper.For2D(..size.Height, ..size.Width, new Assigner2D(size.Height, size.Width, data.Ptr));
|
||||
|
||||
for (int i = 0; i < size.Height; i++)
|
||||
{
|
||||
for (int j = 0; j < size.Width; j++)
|
||||
{
|
||||
if (data[i, j] != unchecked(i * 397 ^ j))
|
||||
if (data.Ptr[(i * size.Width) + j] != unchecked(i * 397 ^ j))
|
||||
{
|
||||
Assert.Fail($"Invalid item at position [{i},{j}], value was {data[i, j]} instead of {unchecked(i * 397 ^ j)}");
|
||||
Assert.Fail($"Invalid item at position [{i},{j}], value was {data.Ptr[(i * size.Width) + j]} instead of {unchecked(i * 397 ^ j)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,21 +97,34 @@ public void Test_ParallelHelper_For2DWithRanges()
|
||||
/// <summary>
|
||||
/// A type implementing <see cref="IAction"/> to initialize a 2D array
|
||||
/// </summary>
|
||||
private readonly struct Assigner2D : IAction2D
|
||||
private readonly unsafe struct Assigner2D : IAction2D
|
||||
{
|
||||
private readonly int[,] array;
|
||||
private readonly int height;
|
||||
private readonly int width;
|
||||
private readonly int* ptr;
|
||||
|
||||
public Assigner2D(int[,] array) => this.array = array;
|
||||
public Assigner2D(int height, int width, int* ptr)
|
||||
{
|
||||
this.height = height;
|
||||
this.width = width;
|
||||
this.ptr = ptr;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Invoke(int i, int j)
|
||||
{
|
||||
if (this.array[i, j] != 0)
|
||||
if ((uint)i >= (uint)this.height ||
|
||||
(uint)j >= (uint)this.width)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid target position [{i},{j}], was {this.array[i, j]} instead of 0");
|
||||
throw new IndexOutOfRangeException($"The target position was invalid, was [{i}, {j}], should've been in [0, {this.height}] and [0, {this.width}]");
|
||||
}
|
||||
|
||||
this.array[i, j] = unchecked(i * 397 ^ j);
|
||||
if (this.ptr[(i * this.width) + j] != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Invalid target position [{i},{j}], was {this.ptr[(i * this.width) + j]} instead of 0");
|
||||
}
|
||||
|
||||
this.ptr[(i * this.width) + j] = unchecked(i * 397 ^ j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
using System.Threading;
|
||||
using Microsoft.Toolkit.HighPerformance.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
namespace UnitTests.HighPerformance.Helpers
|
||||
{
|
||||
@ -19,15 +20,15 @@ public unsafe void Test_ParallelHelper_ForEach_In()
|
||||
{
|
||||
foreach (int count in TestForCounts)
|
||||
{
|
||||
int[] data = CreateRandomData(count);
|
||||
using UnmanagedSpanOwner<int> data = CreateRandomData(count);
|
||||
|
||||
int sum = 0;
|
||||
|
||||
ParallelHelper.ForEach<int, Summer>(data.AsMemory(), new Summer(&sum));
|
||||
ParallelHelper.ForEach<int, Summer>(data.Memory, new Summer(&sum));
|
||||
|
||||
int expected = 0;
|
||||
|
||||
foreach (int n in data)
|
||||
foreach (int n in data.GetSpan())
|
||||
{
|
||||
expected += n;
|
||||
}
|
||||
@ -55,13 +56,13 @@ public unsafe void Test_ParallelHelper_ForEach_In()
|
||||
/// <param name="count">The number of array items to create.</param>
|
||||
/// <returns>An array of random <see cref="int"/> elements.</returns>
|
||||
[Pure]
|
||||
private static int[] CreateRandomData(int count)
|
||||
private static UnmanagedSpanOwner<int> CreateRandomData(int count)
|
||||
{
|
||||
var random = new Random(count);
|
||||
|
||||
int[] data = new int[count];
|
||||
UnmanagedSpanOwner<int> data = new UnmanagedSpanOwner<int>(count);
|
||||
|
||||
foreach (ref int n in data.AsSpan())
|
||||
foreach (ref int n in data.GetSpan())
|
||||
{
|
||||
n = random.Next(0, byte.MaxValue);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using Microsoft.Toolkit.HighPerformance.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using UnitTests.HighPerformance.Shared.Buffers.Internals;
|
||||
|
||||
namespace UnitTests.HighPerformance.Helpers
|
||||
{
|
||||
@ -16,21 +17,26 @@ public void Test_ParallelHelper_ForEach_Ref()
|
||||
{
|
||||
foreach (int count in TestForCounts)
|
||||
{
|
||||
int[] data = CreateRandomData(count);
|
||||
int[] copy = data.AsSpan().ToArray();
|
||||
using UnmanagedSpanOwner<int> data = CreateRandomData(count);
|
||||
using UnmanagedSpanOwner<int> copy = new UnmanagedSpanOwner<int>(count);
|
||||
|
||||
foreach (ref int n in copy.AsSpan())
|
||||
data.GetSpan().CopyTo(copy.GetSpan());
|
||||
|
||||
foreach (ref int n in copy.GetSpan())
|
||||
{
|
||||
n = unchecked(n * 397);
|
||||
}
|
||||
|
||||
ParallelHelper.ForEach(data.AsMemory(), new Multiplier(397));
|
||||
ParallelHelper.ForEach(data.Memory, new Multiplier(397));
|
||||
|
||||
Span<int> dataSpan = data.GetSpan();
|
||||
Span<int> copySpan = copy.GetSpan();
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] != copy[i])
|
||||
if (dataSpan[i] != copySpan[i])
|
||||
{
|
||||
Assert.Fail($"Item #{i} was not a match, was {data[i]} instead of {copy[i]}");
|
||||
Assert.Fail($"Item #{i} was not a match, was {dataSpan[i]} instead of {copySpan[i]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
<Import_RootNamespace>UnitTests.HighPerformance.Shared</Import_RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Buffers\Internals\UnmanagedSpanOwner.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Buffers\Test_MemoryBufferWriter{T}.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Buffers\Test_ArrayPoolBufferWriter{T}.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)Buffers\Test_MemoryOwner{T}.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user