Skip to content

Commit ae2844a

Browse files
committed
Bug fixed in Pin methods, added unit tests
1 parent c523742 commit ae2844a

File tree

3 files changed

+58
-5
lines changed

3 files changed

+58
-5
lines changed

Microsoft.Toolkit.HighPerformance/Buffers/Internals/ArrayMemoryManager{TFrom,TTo}.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ public override unsafe MemoryHandle Pin(int elementIndex = 0)
7373
{
7474
if ((uint)elementIndex >= (uint)(this.length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>()))
7575
{
76-
ThrowArgumentExceptionForInvalidIndex();
76+
ThrowArgumentOutOfRangeExceptionForInvalidIndex();
7777
}
7878

7979
int
80-
bytePrefix = this.offset + Unsafe.SizeOf<TFrom>(),
80+
bytePrefix = this.offset * Unsafe.SizeOf<TFrom>(),
8181
byteSuffix = elementIndex * Unsafe.SizeOf<TTo>(),
8282
byteOffset = bytePrefix + byteSuffix;
8383

@@ -126,7 +126,7 @@ public Memory<T> GetMemory<T>(int offset, int length)
126126
/// <summary>
127127
/// Throws an <see cref="ArgumentOutOfRangeException"/> when the target index for <see cref="Pin"/> is invalid.
128128
/// </summary>
129-
private static void ThrowArgumentExceptionForInvalidIndex()
129+
private static void ThrowArgumentOutOfRangeExceptionForInvalidIndex()
130130
{
131131
throw new ArgumentOutOfRangeException("elementIndex", "The input index is not in the valid range");
132132
}

Microsoft.Toolkit.HighPerformance/Buffers/Internals/ProxyMemoryManager{TFrom,TTo}.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ public override MemoryHandle Pin(int elementIndex = 0)
6464
ThrowArgumentExceptionForInvalidIndex();
6565
}
6666

67-
int byteOffset = elementIndex * Unsafe.SizeOf<TTo>();
67+
int
68+
bytePrefix = this.offset * Unsafe.SizeOf<TFrom>(),
69+
byteSuffix = elementIndex * Unsafe.SizeOf<TTo>(),
70+
byteOffset = bytePrefix + byteSuffix;
6871

6972
#if NETSTANDARD1_4
7073
int
@@ -79,7 +82,7 @@ public override MemoryHandle Pin(int elementIndex = 0)
7982
ThrowArgumentExceptionForInvalidAlignment();
8083
}
8184

82-
return this.memoryManager.Pin(this.length + shiftedOffset);
85+
return this.memoryManager.Pin(shiftedOffset);
8386
}
8487

8588
/// <inheritdoc/>

UnitTests/UnitTests.HighPerformance.Shared/Extensions/Test_MemoryExtensions.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,56 @@ public void Test_MemoryExtensions_FromMemoryManager_CastFromByteAndBack_WithSlic
397397
Assert.IsTrue(span1 == span2);
398398
}
399399

400+
[TestCategory("MemoryExtensions")]
401+
[TestMethod]
402+
[DataRow(64, 0, 0)]
403+
[DataRow(64, 4, 0)]
404+
[DataRow(64, 0, 4)]
405+
[DataRow(64, 4, 4)]
406+
[DataRow(64, 4, 0)]
407+
[DataRow(256, 16, 0)]
408+
[DataRow(256, 4, 16)]
409+
[DataRow(256, 64, 0)]
410+
[DataRow(256, 64, 8)]
411+
public unsafe void Test_MemoryExtensions_FromArray_CastFromByte_Pin(int size, int preOffset, int postOffset)
412+
{
413+
var data = new byte[size];
414+
Memory<byte> memoryOfBytes = data.AsMemory(preOffset);
415+
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>().Slice(postOffset);
416+
417+
using var handle = memoryOfFloats.Pin();
418+
419+
void* p1 = handle.Pointer;
420+
void* p2 = Unsafe.AsPointer(ref data[preOffset + (postOffset * sizeof(float))]);
421+
422+
Assert.IsTrue(p1 == p2);
423+
}
424+
425+
[TestCategory("MemoryExtensions")]
426+
[TestMethod]
427+
[DataRow(64, 0, 0)]
428+
[DataRow(64, 4, 0)]
429+
[DataRow(64, 0, 4)]
430+
[DataRow(64, 4, 4)]
431+
[DataRow(64, 4, 0)]
432+
[DataRow(256, 16, 0)]
433+
[DataRow(256, 4, 16)]
434+
[DataRow(256, 64, 0)]
435+
[DataRow(256, 64, 8)]
436+
public unsafe void Test_MemoryExtensions_FromMemoryManager_CastFromByte_Pin(int size, int preOffset, int postOffset)
437+
{
438+
var data = new ArrayMemoryManager<byte>(size);
439+
Memory<byte> memoryOfBytes = data.Memory.Slice(preOffset);
440+
Memory<float> memoryOfFloats = memoryOfBytes.Cast<byte, float>().Slice(postOffset);
441+
442+
using var handle = memoryOfFloats.Pin();
443+
444+
void* p1 = handle.Pointer;
445+
void* p2 = Unsafe.AsPointer(ref data.GetSpan()[preOffset + (postOffset * sizeof(float))]);
446+
447+
Assert.IsTrue(p1 == p2);
448+
}
449+
400450
[TestCategory("MemoryExtensions")]
401451
[TestMethod]
402452
public void Test_MemoryExtensions_EmptyMemoryStream()

0 commit comments

Comments
 (0)