Skip to content

Commit aba5858

Browse files
Eliminate this = default shortcut when height * width = 0
1 parent 657c697 commit aba5858

File tree

12 files changed

+187
-53
lines changed

12 files changed

+187
-53
lines changed

src/CommunityToolkit.HighPerformance/Memory/Internals/OverflowHelper.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ public static void EnsureIsInNativeIntRange(int height, int width, int pitch)
6464
[MethodImpl(MethodImplOptions.AggressiveInlining)]
6565
public static int ComputeInt32Area(int height, int width, int pitch)
6666
{
67-
return checked(((width + pitch) * Max(unchecked(height - 1), 0)) + width);
67+
if (height <= 0 || width <= 0)
68+
return 0;
69+
70+
return checked(((width + pitch) * (height - 1)) + width);
6871
}
6972
}

src/CommunityToolkit.HighPerformance/Memory/Memory2D{T}.cs

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -362,13 +362,6 @@ public unsafe Memory2D(MemoryManager<T> memoryManager, int offset, int height, i
362362
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
363363
}
364364

365-
if (width == 0 || height == 0)
366-
{
367-
this = default;
368-
369-
return;
370-
}
371-
372365
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
373366
int remaining = length - offset;
374367

@@ -435,16 +428,8 @@ internal unsafe Memory2D(Memory<T> memory, int offset, int height, int width, in
435428
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
436429
}
437430

438-
if (width == 0 || height == 0)
439-
{
440-
this = default;
441-
442-
return;
443-
}
444-
445-
int
446-
area = OverflowHelper.ComputeInt32Area(height, width, pitch),
447-
remaining = memory.Length - offset;
431+
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
432+
int remaining = memory.Length - offset;
448433

449434
if (area > remaining)
450435
{

src/CommunityToolkit.HighPerformance/Memory/ReadOnlyMemory2D{T}.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -382,13 +382,6 @@ public unsafe ReadOnlyMemory2D(MemoryManager<T> memoryManager, int offset, int h
382382
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
383383
}
384384

385-
if (width == 0 || height == 0)
386-
{
387-
this = default;
388-
389-
return;
390-
}
391-
392385
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
393386
int remaining = length - offset;
394387

@@ -455,13 +448,6 @@ internal unsafe ReadOnlyMemory2D(ReadOnlyMemory<T> memory, int offset, int heigh
455448
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
456449
}
457450

458-
if (width == 0 || height == 0)
459-
{
460-
this = default;
461-
462-
return;
463-
}
464-
465451
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
466452
int remaining = memory.Length - offset;
467453

src/CommunityToolkit.HighPerformance/Memory/ReadOnlySpan2D{T}.cs

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,6 @@ public ReadOnlySpan2D(T[] array, int offset, int height, int width, int pitch)
209209
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
210210
}
211211

212-
if (width == 0 || height == 0)
213-
{
214-
this = default;
215-
216-
return;
217-
}
218-
219212
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
220213
int remaining = array.Length - offset;
221214

@@ -459,13 +452,6 @@ internal ReadOnlySpan2D(ReadOnlySpan<T> span, int offset, int height, int width,
459452
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
460453
}
461454

462-
if (width == 0 || height == 0)
463-
{
464-
this = default;
465-
466-
return;
467-
}
468-
469455
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
470456
int remaining = span.Length - offset;
471457

src/CommunityToolkit.HighPerformance/Memory/Span2D{T}.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -531,13 +531,6 @@ internal Span2D(Span<T> span, int offset, int height, int width, int pitch)
531531
ThrowHelper.ThrowArgumentOutOfRangeExceptionForPitch();
532532
}
533533

534-
if (width == 0 || height == 0)
535-
{
536-
this = default;
537-
538-
return;
539-
}
540-
541534
int area = OverflowHelper.ComputeInt32Area(height, width, pitch);
542535
int remaining = span.Length - offset;
543536

tests/CommunityToolkit.HighPerformance.UnitTests/Extensions/Test_MemoryExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,30 @@ public void Test_MemoryExtensions_MemoryStream()
569569
Assert.IsTrue(stream.CanWrite);
570570
}
571571

572+
#if NET6_0_OR_GREATER
573+
[TestMethod]
574+
public void Test_MemoryExtensions_AsMemory2d_Empty()
575+
{
576+
Memory2D<int> empty1 = Array.Empty<int>().AsMemory().AsMemory2D(0, 0);
577+
Assert.IsTrue(empty1.IsEmpty);
578+
Assert.AreEqual(empty1.Length, 0);
579+
Assert.AreEqual(empty1.Width, 0);
580+
Assert.AreEqual(empty1.Height, 0);
581+
582+
Memory2D<int> empty2 = Array.Empty<int>().AsMemory().AsMemory2D(4, 0);
583+
Assert.IsTrue(empty2.IsEmpty);
584+
Assert.AreEqual(empty2.Length, 0);
585+
Assert.AreEqual(empty2.Width, 0);
586+
Assert.AreEqual(empty2.Height, 4);
587+
588+
Memory2D<int> empty3 = Array.Empty<int>().AsMemory().AsMemory2D(0, 7);
589+
Assert.IsTrue(empty3.IsEmpty);
590+
Assert.AreEqual(empty3.Length, 0);
591+
Assert.AreEqual(empty3.Width, 7);
592+
Assert.AreEqual(empty3.Height, 0);
593+
}
594+
#endif
595+
572596
private sealed class ArrayMemoryManager<T> : MemoryManager<T>
573597
where T : unmanaged
574598
{

tests/CommunityToolkit.HighPerformance.UnitTests/Extensions/Test_ReadOnlyMemoryExtensions.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Collections.Generic;
67
using System.IO;
78
using Microsoft.VisualStudio.TestTools.UnitTesting;
89

@@ -34,4 +35,28 @@ public void Test_ReadOnlyMemoryExtensions_MemoryStream()
3435
Assert.AreEqual(stream.Length, memory.Length);
3536
Assert.IsFalse(stream.CanWrite);
3637
}
38+
39+
#if NET6_0_OR_GREATER
40+
[TestMethod]
41+
public void Test_ReadOnlyMemoryExtensions_AsMemory2d_Empty()
42+
{
43+
ReadOnlyMemory2D<int> empty1 = ((ReadOnlyMemory<int>)Array.Empty<int>().AsMemory()).AsMemory2D(0, 0);
44+
Assert.IsTrue(empty1.IsEmpty);
45+
Assert.AreEqual(empty1.Length, 0);
46+
Assert.AreEqual(empty1.Width, 0);
47+
Assert.AreEqual(empty1.Height, 0);
48+
49+
ReadOnlyMemory2D<int> empty2 = ((ReadOnlyMemory<int>)Array.Empty<int>().AsMemory()).AsMemory2D(4, 0);
50+
Assert.IsTrue(empty2.IsEmpty);
51+
Assert.AreEqual(empty2.Length, 0);
52+
Assert.AreEqual(empty2.Width, 0);
53+
Assert.AreEqual(empty2.Height, 4);
54+
55+
ReadOnlyMemory2D<int> empty3 = ((ReadOnlyMemory<int>)Array.Empty<int>().AsMemory()).AsMemory2D(0, 7);
56+
Assert.IsTrue(empty3.IsEmpty);
57+
Assert.AreEqual(empty3.Length, 0);
58+
Assert.AreEqual(empty3.Width, 7);
59+
Assert.AreEqual(empty3.Height, 0);
60+
}
61+
#endif
3762
}

tests/CommunityToolkit.HighPerformance.UnitTests/Extensions/Test_ReadOnlySpanExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,28 @@ public void Test_ReadOnlySpanExtensions_CopyTo_RefEnumerable()
294294

295295
CollectionAssert.AreEqual(array, result);
296296
}
297+
298+
#if NET6_0_OR_GREATER
299+
[TestMethod]
300+
public void Test_ReadOnlySpanExtensions_AsSpan2d_Empty()
301+
{
302+
ReadOnlySpan2D<int> empty1 = ReadOnlySpan<int>.Empty.AsSpan2D(0, 0);
303+
Assert.IsTrue(empty1.IsEmpty);
304+
Assert.AreEqual(empty1.Length, 0);
305+
Assert.AreEqual(empty1.Width, 0);
306+
Assert.AreEqual(empty1.Height, 0);
307+
308+
ReadOnlySpan2D<int> empty2 = ReadOnlySpan<int>.Empty.AsSpan2D(4, 0);
309+
Assert.IsTrue(empty2.IsEmpty);
310+
Assert.AreEqual(empty2.Length, 0);
311+
Assert.AreEqual(empty2.Width, 0);
312+
Assert.AreEqual(empty2.Height, 4);
313+
314+
ReadOnlySpan2D<int> empty3 = ReadOnlySpan<int>.Empty.AsSpan2D(0, 7);
315+
Assert.IsTrue(empty3.IsEmpty);
316+
Assert.AreEqual(empty3.Length, 0);
317+
Assert.AreEqual(empty3.Width, 7);
318+
Assert.AreEqual(empty3.Height, 0);
319+
}
320+
#endif
297321
}

tests/CommunityToolkit.HighPerformance.UnitTests/Extensions/Test_SpanExtensions.cs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,4 +199,45 @@ public void Test_SpanExtensions_CopyTo_RefEnumerable()
199199

200200
CollectionAssert.AreEqual(array, result);
201201
}
202+
203+
#if NET6_0_OR_GREATER
204+
[TestMethod]
205+
public void Test_SpanExtensions_AsSpan2d_Empty()
206+
{
207+
Span2D<int> empty1 = Span<int>.Empty.AsSpan2D(0, 0);
208+
Assert.IsTrue(empty1.IsEmpty);
209+
Assert.AreEqual(empty1.Length, 0);
210+
Assert.AreEqual(empty1.Width, 0);
211+
Assert.AreEqual(empty1.Height, 0);
212+
213+
Span2D<int> empty2 = Span<int>.Empty.AsSpan2D(4, 0);
214+
Assert.IsTrue(empty2.IsEmpty);
215+
Assert.AreEqual(empty2.Length, 0);
216+
Assert.AreEqual(empty2.Width, 0);
217+
Assert.AreEqual(empty2.Height, 4);
218+
219+
Span2D<int> empty3 = Span<int>.Empty.AsSpan2D(0, 7);
220+
Assert.IsTrue(empty3.IsEmpty);
221+
Assert.AreEqual(empty3.Length, 0);
222+
Assert.AreEqual(empty3.Width, 7);
223+
Assert.AreEqual(empty3.Height, 0);
224+
}
225+
226+
[TestMethod]
227+
public void Test_SpanExtensions_AsSpan2d_Copy()
228+
{
229+
int[,] array = new int[2, 3];
230+
int[] values1 = { 1, 2, 3, 4, 5, 6 };
231+
// Copy a span to a target row and column with valid lengths
232+
values1.AsSpan().AsSpan2D(2, 3).CopyTo(array);
233+
int[,] result = new[,]
234+
{
235+
{ 1, 2, 3 },
236+
{ 4, 5, 6 },
237+
};
238+
239+
CollectionAssert.AreEqual(array, result);
240+
_ = Assert.ThrowsException<ArgumentException>(() => values1.AsSpan().AsSpan2D(3, 2).CopyTo(array));
241+
}
242+
#endif
202243
}

tests/CommunityToolkit.HighPerformance.UnitTests/Memory/Test_Memory2D{T}.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Buffers;
67
using System.Runtime.CompilerServices;
8+
using CommunityToolkit.HighPerformance.UnitTests.Buffers.Internals;
79
using Microsoft.VisualStudio.TestTools.UnitTesting;
810

911
namespace CommunityToolkit.HighPerformance.UnitTests;
@@ -43,6 +45,27 @@ public void Test_Memory2DT_Empty()
4345
Assert.AreEqual(empty4.Length, 0);
4446
Assert.AreEqual(empty4.Width, 7);
4547
Assert.AreEqual(empty4.Height, 0);
48+
49+
#if NET6_0_OR_GREATER
50+
MemoryManager<int> memoryManager = new UnmanagedSpanOwner<int>(1);
51+
Memory2D<int> empty5 = new (memoryManager, 0, 0);
52+
Assert.IsTrue(empty5.IsEmpty);
53+
Assert.AreEqual(empty5.Length, 0);
54+
Assert.AreEqual(empty5.Width, 0);
55+
Assert.AreEqual(empty5.Height, 0);
56+
57+
Memory2D<int> empty6 = new (memoryManager, 4, 0);
58+
Assert.IsTrue(empty6.IsEmpty);
59+
Assert.AreEqual(empty6.Length, 0);
60+
Assert.AreEqual(empty6.Width, 0);
61+
Assert.AreEqual(empty6.Height, 4);
62+
63+
Memory2D<int> empty7 = new (memoryManager, 0, 7);
64+
Assert.IsTrue(empty7.IsEmpty);
65+
Assert.AreEqual(empty7.Length, 0);
66+
Assert.AreEqual(empty7.Width, 7);
67+
Assert.AreEqual(empty7.Height, 0);
68+
#endif
4669
}
4770

4871
[TestMethod]

0 commit comments

Comments
 (0)