Reduce IntersectionType[] allocations (#3924)

* Eliminate LineCanvas.Has params array allocation

Inline ReadOnlySpan arguments do not incur heap allocation compared to regular arrays.

* Allocate once LineCanvas.Exactly corner intersection arrays

---------

Co-authored-by: Tig <tig@users.noreply.github.com>
This commit is contained in:
Tonttu
2025-02-27 19:44:39 +02:00
committed by GitHub
parent e632a12049
commit 255114f0f2

View File

@@ -532,8 +532,8 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverHorizontal, [IntersectionType.PassOverHorizontal,
IntersectionType.PassOverVertical IntersectionType.PassOverVertical]
)) ))
{ {
return IntersectionRuneType.Cross; return IntersectionRuneType.Cross;
@@ -541,9 +541,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverVertical, [IntersectionType.PassOverVertical,
IntersectionType.StartLeft, IntersectionType.StartLeft,
IntersectionType.StartRight IntersectionType.StartRight]
)) ))
{ {
return IntersectionRuneType.Cross; return IntersectionRuneType.Cross;
@@ -551,9 +551,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverHorizontal, [IntersectionType.PassOverHorizontal,
IntersectionType.StartUp, IntersectionType.StartUp,
IntersectionType.StartDown IntersectionType.StartDown]
)) ))
{ {
return IntersectionRuneType.Cross; return IntersectionRuneType.Cross;
@@ -561,10 +561,10 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.StartLeft, [IntersectionType.StartLeft,
IntersectionType.StartRight, IntersectionType.StartRight,
IntersectionType.StartUp, IntersectionType.StartUp,
IntersectionType.StartDown IntersectionType.StartDown]
)) ))
{ {
return IntersectionRuneType.Cross; return IntersectionRuneType.Cross;
@@ -574,38 +574,22 @@ public class LineCanvas : IDisposable
#region Corner Conditions #region Corner Conditions
if (Exactly ( if (Exactly (set, CornerIntersections.UpperLeft))
set,
IntersectionType.StartRight,
IntersectionType.StartDown
))
{ {
return IntersectionRuneType.ULCorner; return IntersectionRuneType.ULCorner;
} }
if (Exactly ( if (Exactly (set, CornerIntersections.UpperRight))
set,
IntersectionType.StartLeft,
IntersectionType.StartDown
))
{ {
return IntersectionRuneType.URCorner; return IntersectionRuneType.URCorner;
} }
if (Exactly ( if (Exactly (set, CornerIntersections.LowerRight))
set,
IntersectionType.StartUp,
IntersectionType.StartLeft
))
{ {
return IntersectionRuneType.LRCorner; return IntersectionRuneType.LRCorner;
} }
if (Exactly ( if (Exactly (set, CornerIntersections.LowerLeft))
set,
IntersectionType.StartUp,
IntersectionType.StartRight
))
{ {
return IntersectionRuneType.LLCorner; return IntersectionRuneType.LLCorner;
} }
@@ -616,8 +600,8 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverHorizontal, [IntersectionType.PassOverHorizontal,
IntersectionType.StartDown IntersectionType.StartDown]
)) ))
{ {
return IntersectionRuneType.TopTee; return IntersectionRuneType.TopTee;
@@ -625,9 +609,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.StartRight, [IntersectionType.StartRight,
IntersectionType.StartLeft, IntersectionType.StartLeft,
IntersectionType.StartDown IntersectionType.StartDown]
)) ))
{ {
return IntersectionRuneType.TopTee; return IntersectionRuneType.TopTee;
@@ -635,8 +619,8 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverHorizontal, [IntersectionType.PassOverHorizontal,
IntersectionType.StartUp IntersectionType.StartUp]
)) ))
{ {
return IntersectionRuneType.BottomTee; return IntersectionRuneType.BottomTee;
@@ -644,9 +628,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.StartRight, [IntersectionType.StartRight,
IntersectionType.StartLeft, IntersectionType.StartLeft,
IntersectionType.StartUp IntersectionType.StartUp]
)) ))
{ {
return IntersectionRuneType.BottomTee; return IntersectionRuneType.BottomTee;
@@ -654,8 +638,8 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverVertical, [IntersectionType.PassOverVertical,
IntersectionType.StartRight IntersectionType.StartRight]
)) ))
{ {
return IntersectionRuneType.LeftTee; return IntersectionRuneType.LeftTee;
@@ -663,9 +647,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.StartRight, [IntersectionType.StartRight,
IntersectionType.StartDown, IntersectionType.StartDown,
IntersectionType.StartUp IntersectionType.StartUp]
)) ))
{ {
return IntersectionRuneType.LeftTee; return IntersectionRuneType.LeftTee;
@@ -673,8 +657,8 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.PassOverVertical, [IntersectionType.PassOverVertical,
IntersectionType.StartLeft IntersectionType.StartLeft]
)) ))
{ {
return IntersectionRuneType.RightTee; return IntersectionRuneType.RightTee;
@@ -682,9 +666,9 @@ public class LineCanvas : IDisposable
if (Has ( if (Has (
set, set,
IntersectionType.StartLeft, [IntersectionType.StartLeft,
IntersectionType.StartDown, IntersectionType.StartDown,
IntersectionType.StartUp IntersectionType.StartUp]
)) ))
{ {
return IntersectionRuneType.RightTee; return IntersectionRuneType.RightTee;
@@ -712,7 +696,7 @@ public class LineCanvas : IDisposable
/// <param name="intersects"></param> /// <param name="intersects"></param>
/// <param name="types"></param> /// <param name="types"></param>
/// <returns></returns> /// <returns></returns>
private bool Has (HashSet<IntersectionType> intersects, params IntersectionType [] types) private bool Has (HashSet<IntersectionType> intersects, ReadOnlySpan<IntersectionType> types)
{ {
foreach (var type in types) foreach (var type in types)
{ {
@@ -724,6 +708,25 @@ public class LineCanvas : IDisposable
return true; return true;
} }
/// <summary>
/// Preallocated arrays for <see cref="GetRuneTypeForIntersects"/> calls to <see cref="Exactly"/>.
/// </summary>
/// <remarks>
/// Optimization to avoid array allocation for each call from array params. Please do not edit the arrays at runtime. :)
///
/// More ideal solution would be to change <see cref="Exactly"/> to take ReadOnlySpan instead of an array
/// but that would require replacing the HashSet.SetEquals call.
/// </remarks>
private static class CornerIntersections
{
// Names matching #region "Corner Conditions" IntersectionRuneType
internal static readonly IntersectionType[] UpperLeft = [IntersectionType.StartRight, IntersectionType.StartDown];
internal static readonly IntersectionType[] UpperRight = [IntersectionType.StartLeft, IntersectionType.StartDown];
internal static readonly IntersectionType[] LowerRight = [IntersectionType.StartUp, IntersectionType.StartLeft];
internal static readonly IntersectionType[] LowerLeft = [IntersectionType.StartUp, IntersectionType.StartRight];
}
private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver
{ {
public override void SetGlyphs () public override void SetGlyphs ()