< Summary

Information
Class: Trailblazer.Pathing.NavigationIncomingSurfaceEdgeEnumerator
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/NavigationIncomingSurfaceEdgeEnumerator.cs
Line coverage
100%
Covered lines: 93
Uncovered lines: 0
Coverable lines: 93
Total lines: 184
Line coverage: 100%
Branch coverage
100%
Covered branches: 34
Total branches: 34
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%22100%
MoveNext()100%44100%
AdvanceOne(...)100%11100%
AdvanceOne(...)100%11100%
AdvanceOneCore(...)100%2020100%
MatchesIncomingCandidate(...)100%88100%
ClearIncomingCandidate()100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/NavigationIncomingSurfaceEdgeEnumerator.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationIncomingSurfaceEdgeEnumerator.cs
 3//=======================================================================
 4// MIT License, Copyright (c) 2024-present David Oravsky (mrdav30)
 5// See LICENSE file in the project root for full license information.
 6//=======================================================================
 7
 8namespace Trailblazer.Pathing;
 9
 10/// <summary>Enumerates original forward edges into one destination in canonical order.</summary>
 11internal struct NavigationIncomingSurfaceEdgeEnumerator
 12{
 13    private readonly NavigationWorldGraph? _graph;
 14    private readonly NavigationNodeRef _destination;
 15    private readonly NavigationCellAddress _destinationAddress;
 16    private readonly bool _structural;
 17    private NavigationSurfaceEdgeEnumerator _incomingCandidates;
 18    private NavigationSurfaceEdgeEnumerator _outgoingEdges;
 19    private NavigationGraphEdge _incomingCandidate;
 20    private NavigationNodeRef _predecessor;
 21    private bool _hasIncomingCandidate;
 22
 23    internal NavigationIncomingSurfaceEdgeEnumerator(
 24        NavigationWorldGraph graph,
 25        NavigationNodeRef destination,
 26        bool structural = false)
 27    {
 11116728        _destination = destination;
 11116729        _outgoingEdges = default;
 11116730        _incomingCandidate = default;
 11116731        _predecessor = default;
 11116732        _hasIncomingCandidate = false;
 11116733        _structural = structural;
 11116734        Current = default;
 11116735        bool found = graph.TryGetNodeAddress(destination, out _destinationAddress);
 36        System.Diagnostics.Debug.Assert(found,
 37            "incoming enumeration receives a destination owned by this immutable graph");
 11116738        if (structural)
 39        {
 40            System.Diagnostics.Debug.Assert(graph.HasEffectiveCell(_destinationAddress),
 41                "structural enumeration receives an effective graph-owned destination");
 42        }
 43        else
 44        {
 2347745            bool hasState = graph.TryGetNodeState(
 2347746                destination,
 2347747                out NavigationNodeState state);
 48            System.Diagnostics.Debug.Assert(hasState && state.IsPresent,
 49                "runtime incoming enumeration receives a present graph-owned destination");
 50        }
 51
 11116752        _graph = graph;
 11116753        _incomingCandidates = new NavigationSurfaceEdgeEnumerator(
 11116754            graph,
 11116755            destination,
 11116756            incoming: true,
 11116757            includeNative: true,
 11116758            includeAutomaticSeams: true,
 11116759            structural: structural);
 11116760    }
 61
 62    internal NavigationIncomingSurfaceEdge Current { get; private set; }
 63
 64    internal bool MoveNext()
 65    {
 12002066        int unbounded = int.MaxValue;
 67        while (true)
 68        {
 22003869            NavigationSurfaceEdgeAdvanceStatus status = AdvanceOne(
 22003870                (NavigationWorkMeter?)null,
 22003871                ref unbounded);
 22003872            if (status == NavigationSurfaceEdgeAdvanceStatus.Edge)
 10001673                return true;
 12002274            if (status == NavigationSurfaceEdgeAdvanceStatus.Complete)
 2000475                return false;
 76        }
 77    }
 78
 79    internal NavigationSurfaceEdgeAdvanceStatus AdvanceOne(
 80        NavigationWorkMeter? meter,
 81        ref int edgeStepRemaining)
 23886282        => AdvanceOneCore(meter, null, ref edgeStepRemaining);
 83
 84    internal NavigationSurfaceEdgeAdvanceStatus AdvanceOne(
 85        MaintenanceWorkMeter meter,
 86        ref int edgeStepRemaining)
 97173587        => AdvanceOneCore(null, meter, ref edgeStepRemaining);
 88
 89    private NavigationSurfaceEdgeAdvanceStatus AdvanceOneCore(
 90        NavigationWorkMeter? queryMeter,
 91        MaintenanceWorkMeter? maintenanceMeter,
 92        ref int edgeStepRemaining)
 93    {
 94        System.Diagnostics.Debug.Assert(_graph != null,
 95            "incoming enumeration advances only after graph-owned initialization");
 96
 97        while (true)
 98        {
 142744799            if (!_hasIncomingCandidate)
 100            {
 724266101                NavigationSurfaceEdgeAdvanceStatus incomingStatus =
 724266102                    queryMeter != null
 724266103                        ? _incomingCandidates.AdvanceOne(queryMeter, ref edgeStepRemaining)
 724266104                        : maintenanceMeter != null
 724266105                            ? _incomingCandidates.AdvanceOne(
 724266106                                maintenanceMeter,
 724266107                                ref edgeStepRemaining)
 724266108                            : _incomingCandidates.AdvanceOne(
 724266109                                (NavigationWorkMeter?)null,
 724266110                                ref edgeStepRemaining);
 724266111                if (incomingStatus == NavigationSurfaceEdgeAdvanceStatus.Complete)
 111151112                    Current = default;
 724266113                if (incomingStatus != NavigationSurfaceEdgeAdvanceStatus.Edge)
 435527114                    return incomingStatus;
 115
 288739116                _incomingCandidate = _incomingCandidates.Current;
 288739117                _predecessor = _incomingCandidate.Target;
 288739118                _outgoingEdges = _structural
 288739119                    ? _graph.EnumerateStructuralSurfaceEdges(_predecessor)
 288739120                    : _graph.EnumerateSurfaceEdges(_predecessor);
 288739121                _hasIncomingCandidate = true;
 122            }
 123
 991920124            NavigationSurfaceEdgeAdvanceStatus outgoingStatus =
 991920125                queryMeter != null
 991920126                    ? _outgoingEdges.AdvanceOne(queryMeter, ref edgeStepRemaining)
 991920127                    : maintenanceMeter != null
 991920128                        ? _outgoingEdges.AdvanceOne(
 991920129                            maintenanceMeter,
 991920130                            ref edgeStepRemaining)
 991920131                        : _outgoingEdges.AdvanceOne(
 991920132                            (NavigationWorkMeter?)null,
 991920133                            ref edgeStepRemaining);
 991920134            if (outgoingStatus != NavigationSurfaceEdgeAdvanceStatus.Edge)
 135            {
 136                System.Diagnostics.Debug.Assert(
 137                    outgoingStatus != NavigationSurfaceEdgeAdvanceStatus.Complete);
 486333138                return outgoingStatus;
 139            }
 140
 505587141            NavigationGraphEdge forwardEdge = _outgoingEdges.Current;
 505587142            if (!MatchesIncomingCandidate(forwardEdge))
 143                continue;
 144
 288737145            Current = new NavigationIncomingSurfaceEdge(
 288737146                _predecessor,
 288737147                forwardEdge,
 288737148                new NavigationSelectedEdgeRef(
 288737149                    _destinationAddress,
 288737150                    TraversalMedium.Solid,
 288737151                    _outgoingEdges.CurrentOrdinal));
 288737152            ClearIncomingCandidate();
 288737153            return NavigationSurfaceEdgeAdvanceStatus.Edge;
 154        }
 155    }
 156
 157    private bool MatchesIncomingCandidate(in NavigationGraphEdge forwardEdge)
 158    {
 505587159        if (!forwardEdge.Target.Equals(_destination)
 505587160            || forwardEdge.Kind != _incomingCandidate.Kind)
 161        {
 212794162            return false;
 163        }
 164
 292793165        return forwardEdge.Kind switch
 292793166        {
 32716167            NavigationGraphEdgeKind.Explicit => ReferenceEquals(
 32716168                forwardEdge.ExplicitConnection,
 32716169                _incomingCandidate.ExplicitConnection),
 60788170            NavigationGraphEdgeKind.Seam => ReferenceEquals(
 60788171                forwardEdge.AutomaticSeam.Pair,
 60788172                _incomingCandidate.AutomaticSeam.Pair),
 199289173            _ => true
 292793174        };
 175    }
 176
 177    private void ClearIncomingCandidate()
 178    {
 288737179        _outgoingEdges = default;
 288737180        _incomingCandidate = default;
 288737181        _predecessor = default;
 288737182        _hasIncomingCandidate = false;
 288737183    }
 184}