Skip to content

Commit 255114f

Browse files
TheTonttutig
andauthored
Reduce IntersectionType[] allocations (gui-cs#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 <[email protected]>
1 parent e632a12 commit 255114f

File tree

1 file changed

+48
-45
lines changed

1 file changed

+48
-45
lines changed

Terminal.Gui/Drawing/LineCanvas/LineCanvas.cs

+48-45
Original file line numberDiff line numberDiff line change
@@ -532,39 +532,39 @@ private IntersectionRuneType GetRuneTypeForIntersects (ReadOnlySpan<Intersection
532532

533533
if (Has (
534534
set,
535-
IntersectionType.PassOverHorizontal,
536-
IntersectionType.PassOverVertical
535+
[IntersectionType.PassOverHorizontal,
536+
IntersectionType.PassOverVertical]
537537
))
538538
{
539539
return IntersectionRuneType.Cross;
540540
}
541541

542542
if (Has (
543543
set,
544-
IntersectionType.PassOverVertical,
544+
[IntersectionType.PassOverVertical,
545545
IntersectionType.StartLeft,
546-
IntersectionType.StartRight
546+
IntersectionType.StartRight]
547547
))
548548
{
549549
return IntersectionRuneType.Cross;
550550
}
551551

552552
if (Has (
553553
set,
554-
IntersectionType.PassOverHorizontal,
554+
[IntersectionType.PassOverHorizontal,
555555
IntersectionType.StartUp,
556-
IntersectionType.StartDown
556+
IntersectionType.StartDown]
557557
))
558558
{
559559
return IntersectionRuneType.Cross;
560560
}
561561

562562
if (Has (
563563
set,
564-
IntersectionType.StartLeft,
564+
[IntersectionType.StartLeft,
565565
IntersectionType.StartRight,
566566
IntersectionType.StartUp,
567-
IntersectionType.StartDown
567+
IntersectionType.StartDown]
568568
))
569569
{
570570
return IntersectionRuneType.Cross;
@@ -574,38 +574,22 @@ private IntersectionRuneType GetRuneTypeForIntersects (ReadOnlySpan<Intersection
574574

575575
#region Corner Conditions
576576

577-
if (Exactly (
578-
set,
579-
IntersectionType.StartRight,
580-
IntersectionType.StartDown
581-
))
577+
if (Exactly (set, CornerIntersections.UpperLeft))
582578
{
583579
return IntersectionRuneType.ULCorner;
584580
}
585581

586-
if (Exactly (
587-
set,
588-
IntersectionType.StartLeft,
589-
IntersectionType.StartDown
590-
))
582+
if (Exactly (set, CornerIntersections.UpperRight))
591583
{
592584
return IntersectionRuneType.URCorner;
593585
}
594586

595-
if (Exactly (
596-
set,
597-
IntersectionType.StartUp,
598-
IntersectionType.StartLeft
599-
))
587+
if (Exactly (set, CornerIntersections.LowerRight))
600588
{
601589
return IntersectionRuneType.LRCorner;
602590
}
603591

604-
if (Exactly (
605-
set,
606-
IntersectionType.StartUp,
607-
IntersectionType.StartRight
608-
))
592+
if (Exactly (set, CornerIntersections.LowerLeft))
609593
{
610594
return IntersectionRuneType.LLCorner;
611595
}
@@ -616,75 +600,75 @@ private IntersectionRuneType GetRuneTypeForIntersects (ReadOnlySpan<Intersection
616600

617601
if (Has (
618602
set,
619-
IntersectionType.PassOverHorizontal,
620-
IntersectionType.StartDown
603+
[IntersectionType.PassOverHorizontal,
604+
IntersectionType.StartDown]
621605
))
622606
{
623607
return IntersectionRuneType.TopTee;
624608
}
625609

626610
if (Has (
627611
set,
628-
IntersectionType.StartRight,
612+
[IntersectionType.StartRight,
629613
IntersectionType.StartLeft,
630-
IntersectionType.StartDown
614+
IntersectionType.StartDown]
631615
))
632616
{
633617
return IntersectionRuneType.TopTee;
634618
}
635619

636620
if (Has (
637621
set,
638-
IntersectionType.PassOverHorizontal,
639-
IntersectionType.StartUp
622+
[IntersectionType.PassOverHorizontal,
623+
IntersectionType.StartUp]
640624
))
641625
{
642626
return IntersectionRuneType.BottomTee;
643627
}
644628

645629
if (Has (
646630
set,
647-
IntersectionType.StartRight,
631+
[IntersectionType.StartRight,
648632
IntersectionType.StartLeft,
649-
IntersectionType.StartUp
633+
IntersectionType.StartUp]
650634
))
651635
{
652636
return IntersectionRuneType.BottomTee;
653637
}
654638

655639
if (Has (
656640
set,
657-
IntersectionType.PassOverVertical,
658-
IntersectionType.StartRight
641+
[IntersectionType.PassOverVertical,
642+
IntersectionType.StartRight]
659643
))
660644
{
661645
return IntersectionRuneType.LeftTee;
662646
}
663647

664648
if (Has (
665649
set,
666-
IntersectionType.StartRight,
650+
[IntersectionType.StartRight,
667651
IntersectionType.StartDown,
668-
IntersectionType.StartUp
652+
IntersectionType.StartUp]
669653
))
670654
{
671655
return IntersectionRuneType.LeftTee;
672656
}
673657

674658
if (Has (
675659
set,
676-
IntersectionType.PassOverVertical,
677-
IntersectionType.StartLeft
660+
[IntersectionType.PassOverVertical,
661+
IntersectionType.StartLeft]
678662
))
679663
{
680664
return IntersectionRuneType.RightTee;
681665
}
682666

683667
if (Has (
684668
set,
685-
IntersectionType.StartLeft,
669+
[IntersectionType.StartLeft,
686670
IntersectionType.StartDown,
687-
IntersectionType.StartUp
671+
IntersectionType.StartUp]
688672
))
689673
{
690674
return IntersectionRuneType.RightTee;
@@ -712,7 +696,7 @@ private IntersectionRuneType GetRuneTypeForIntersects (ReadOnlySpan<Intersection
712696
/// <param name="intersects"></param>
713697
/// <param name="types"></param>
714698
/// <returns></returns>
715-
private bool Has (HashSet<IntersectionType> intersects, params IntersectionType [] types)
699+
private bool Has (HashSet<IntersectionType> intersects, ReadOnlySpan<IntersectionType> types)
716700
{
717701
foreach (var type in types)
718702
{
@@ -724,6 +708,25 @@ private bool Has (HashSet<IntersectionType> intersects, params IntersectionType
724708
return true;
725709
}
726710

711+
712+
/// <summary>
713+
/// Preallocated arrays for <see cref="GetRuneTypeForIntersects"/> calls to <see cref="Exactly"/>.
714+
/// </summary>
715+
/// <remarks>
716+
/// Optimization to avoid array allocation for each call from array params. Please do not edit the arrays at runtime. :)
717+
///
718+
/// More ideal solution would be to change <see cref="Exactly"/> to take ReadOnlySpan instead of an array
719+
/// but that would require replacing the HashSet.SetEquals call.
720+
/// </remarks>
721+
private static class CornerIntersections
722+
{
723+
// Names matching #region "Corner Conditions" IntersectionRuneType
724+
internal static readonly IntersectionType[] UpperLeft = [IntersectionType.StartRight, IntersectionType.StartDown];
725+
internal static readonly IntersectionType[] UpperRight = [IntersectionType.StartLeft, IntersectionType.StartDown];
726+
internal static readonly IntersectionType[] LowerRight = [IntersectionType.StartUp, IntersectionType.StartLeft];
727+
internal static readonly IntersectionType[] LowerLeft = [IntersectionType.StartUp, IntersectionType.StartRight];
728+
}
729+
727730
private class BottomTeeIntersectionRuneResolver : IntersectionRuneResolver
728731
{
729732
public override void SetGlyphs ()

0 commit comments

Comments
 (0)