< Summary

Information
Class: Trailblazer.Pathing.NavigationSurfaceEdgeEnumerator
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/NavigationSurfaceEdgeEnumerator.cs
Line coverage
100%
Covered lines: 247
Uncovered lines: 0
Coverable lines: 247
Total lines: 444
Line coverage: 100%
Branch coverage
100%
Covered branches: 130
Total branches: 130
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%1212100%
get_CurrentOrdinal()100%11100%
MoveNext()100%44100%
AdvanceOne(...)100%11100%
AdvanceOne(...)100%11100%
AdvanceOne(...)100%11100%
AdvanceOneCore(...)100%4646100%
TrySelectReadyEdge()100%2626100%
IsSelectionReady(...)100%44100%
FillExplicit(...)100%1010100%
FillSeam(...)100%44100%
IsSeamEndpointEligible(...)100%22100%
TryConsumeCandidate(...)100%2020100%
Compare(...)100%22100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// NavigationSurfaceEdgeEnumerator.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
 10internal enum NavigationSurfaceEdgeAdvanceStatus : byte
 11{
 12    Pending = 0,
 13    Edge = 1,
 14    Complete = 2,
 15    Blocked = 3
 16}
 17
 18/// <summary>Merges native, explicit, and automatic-seam edges in durable canonical order.</summary>
 19internal struct NavigationSurfaceEdgeEnumerator
 20{
 21    private readonly NavigationWorldGraph? _graph;
 22    private readonly NavigationCellAddress _origin;
 23    private NavigationPagedSequence<NavigationConnectionOwnerKey>.Enumerator _incident;
 24    private NavigationNativeSurfaceEdgeEnumerator _native;
 25    private NavigationAutomaticSeamIndex.EndpointEnumerator _seam;
 26    private readonly bool _incoming;
 27    private readonly bool _structural;
 28    private bool _nativeComplete;
 29    private bool _explicitComplete;
 30    private bool _seamComplete;
 31    private bool _hasNative;
 32    private bool _hasExplicit;
 33    private bool _hasSeam;
 34    private bool _nativeNeedsDebit;
 35    private bool _hasPendingExplicitOwner;
 36    private bool _hasPendingSeam;
 37    private NavigationConnectionOwnerKey _pendingExplicitOwner;
 38    private NavigationAutomaticSeamRef _pendingSeam;
 39    private NavigationGraphEdge _nativeEdge;
 40    private NavigationGraphEdge _explicitEdge;
 41    private NavigationGraphEdge _seamEdge;
 42    private NavigationCellAddress _nativeEndpoint;
 43    private NavigationCellAddress _explicitEndpoint;
 44    private NavigationCellAddress _seamEndpoint;
 45    private int _currentOrdinal;
 46
 47    internal NavigationSurfaceEdgeEnumerator(
 48        NavigationWorldGraph graph,
 49        NavigationNodeRef origin,
 50        bool incoming,
 51        bool includeNative,
 52        bool includeAutomaticSeams,
 53        bool structural = false)
 54    {
 52116455        _graph = graph;
 52116456        _incoming = incoming;
 52116457        _structural = structural;
 52116458        _nativeComplete = !includeNative;
 52116459        _explicitComplete = false;
 52116460        _seamComplete = !includeAutomaticSeams;
 52116461        _hasNative = false;
 52116462        _hasExplicit = false;
 52116463        _hasSeam = false;
 52116464        _nativeNeedsDebit = false;
 52116465        _hasPendingExplicitOwner = false;
 52116466        _hasPendingSeam = false;
 52116467        _pendingExplicitOwner = default;
 52116468        _pendingSeam = default;
 52116469        _nativeEdge = default;
 52116470        _explicitEdge = default;
 52116471        _seamEdge = default;
 52116472        _nativeEndpoint = default;
 52116473        _explicitEndpoint = default;
 52116474        _seamEndpoint = default;
 52116475        _currentOrdinal = -1;
 52116476        Current = default;
 52116477        bool found = graph.TryGetNodeAddress(origin, out _origin);
 78        System.Diagnostics.Debug.Assert(found);
 52116479        if (structural
 52116480            ? !graph.HasEffectiveCell(_origin)
 52116481            : !graph.TryGetNodeState(origin, out NavigationNodeState state)
 52116482                || !state.IsPresent)
 83        {
 4084            _graph = null;
 4085            _origin = default;
 4086            _incident = default;
 4087            _native = default;
 4088            _seam = default;
 4089            return;
 90        }
 52112491        NavigationPagedSequence<NavigationConnectionOwnerKey> endpoints =
 52112492            graph.ExplicitConnections.GetEndpointOwnerRow(_origin);
 52112493        _incident = endpoints.GetEnumerator();
 52112494        _seam = includeAutomaticSeams
 52112495            ? graph.AutomaticSeams.GetActiveEndpointEnumerator(_origin)
 52112496            : default;
 52112497        _native = includeNative
 52112498            ? structural
 52112499                ? graph.EnumerateStructuralNativeSurfaceEdges(origin)
 521124100                : graph.EnumerateNativeSurfaceEdges(origin)
 521124101            : default;
 521124102    }
 103
 104    internal NavigationGraphEdge Current { get; private set; }
 105
 313310106    internal int CurrentOrdinal => _currentOrdinal;
 107
 108    internal bool MoveNext()
 109    {
 60577110        int unbounded = int.MaxValue;
 111        while (true)
 112        {
 80777113            NavigationSurfaceEdgeAdvanceStatus status = AdvanceOne(
 80777114                (NavigationWorkMeter?)null,
 80777115                ref unbounded);
 80777116            if (status == NavigationSurfaceEdgeAdvanceStatus.Edge)
 40355117                return true;
 40422118            if (status == NavigationSurfaceEdgeAdvanceStatus.Complete)
 20222119                return false;
 120        }
 121    }
 122
 123    internal NavigationSurfaceEdgeAdvanceStatus AdvanceOne(
 124        NavigationWorkMeter? meter,
 125        ref int edgeStepRemaining)
 126    {
 565507127        GuideSampleWorkMeter unused = default;
 565507128        return AdvanceOneCore(
 565507129            meter,
 565507130            null,
 565507131            ref unused,
 565507132            useGuideMeter: false,
 565507133            ref edgeStepRemaining);
 134    }
 135
 136    internal NavigationSurfaceEdgeAdvanceStatus AdvanceOne(
 137        MaintenanceWorkMeter meter,
 138        ref int edgeStepRemaining)
 139    {
 1820660140        GuideSampleWorkMeter unused = default;
 1820660141        return AdvanceOneCore(
 1820660142            null,
 1820660143            meter,
 1820660144            ref unused,
 1820660145            useGuideMeter: false,
 1820660146            ref edgeStepRemaining);
 147    }
 148
 149    internal NavigationSurfaceEdgeAdvanceStatus AdvanceOne(
 150        ref GuideSampleWorkMeter meter,
 5974151        ref int edgeStepRemaining) => AdvanceOneCore(
 5974152            null,
 5974153            null,
 5974154            ref meter,
 5974155            useGuideMeter: true,
 5974156            ref edgeStepRemaining);
 157
 158    private NavigationSurfaceEdgeAdvanceStatus AdvanceOneCore(
 159        NavigationWorkMeter? queryMeter,
 160        MaintenanceWorkMeter? maintenanceMeter,
 161        ref GuideSampleWorkMeter guideMeter,
 162        bool useGuideMeter,
 163        ref int edgeStepRemaining)
 164    {
 2392141165        if (_graph == null)
 40166            return NavigationSurfaceEdgeAdvanceStatus.Complete;
 167
 2392101168        if (!_hasNative && !_nativeComplete)
 169        {
 1566713170            if (!_nativeNeedsDebit)
 171            {
 1566561172                if (maintenanceMeter != null)
 173                {
 1358726174                    NavigationSurfaceEdgeAdvanceStatus nativeStatus =
 1358726175                        _native.AdvanceOne(maintenanceMeter, ref edgeStepRemaining);
 1358726176                    if (nativeStatus == NavigationSurfaceEdgeAdvanceStatus.Blocked)
 211177                        return nativeStatus;
 1358515178                    if (nativeStatus == NavigationSurfaceEdgeAdvanceStatus.Pending)
 543314179                        return nativeStatus;
 815201180                    if (nativeStatus == NavigationSurfaceEdgeAdvanceStatus.Complete)
 184689181                        _nativeComplete = true;
 182                    else
 183                    {
 630512184                        _nativeEdge = _native.Current;
 630512185                        _graph.TryGetNodeAddress(_nativeEdge.Target, out _nativeEndpoint);
 630512186                        _hasNative = true;
 630512187                        return TrySelectReadyEdge();
 188                    }
 189                }
 207835190                else if (!_native.MoveNext())
 191                {
 129464192                    _nativeComplete = true;
 193                }
 194                else
 195                {
 78371196                    _nativeEdge = _native.Current;
 78371197                    _graph.TryGetNodeAddress(_nativeEdge.Target, out _nativeEndpoint);
 78371198                    _nativeNeedsDebit = true;
 199                }
 200            }
 392676201            if (_nativeNeedsDebit)
 202            {
 78523203                if (!TryConsumeCandidate(
 78523204                        queryMeter,
 78523205                        maintenanceMeter,
 78523206                        ref guideMeter,
 78523207                        useGuideMeter,
 78523208                        ref edgeStepRemaining))
 175209                    return NavigationSurfaceEdgeAdvanceStatus.Blocked;
 78348210                _nativeNeedsDebit = false;
 78348211                _hasNative = true;
 78348212                return TrySelectReadyEdge();
 213            }
 214        }
 215
 1139541216        if (!_hasExplicit && !_explicitComplete)
 217        {
 685466218            if (!_hasPendingExplicitOwner)
 219            {
 685455220                if (!_incident.MoveNext())
 475741221                    _explicitComplete = true;
 222                else
 223                {
 209714224                    _pendingExplicitOwner = _incident.Current;
 209714225                    _hasPendingExplicitOwner = true;
 226                }
 227            }
 685466228            if (_hasPendingExplicitOwner)
 229            {
 209725230                if (!TryConsumeCandidate(
 209725231                        queryMeter,
 209725232                        maintenanceMeter,
 209725233                        ref guideMeter,
 209725234                        useGuideMeter,
 209725235                        ref edgeStepRemaining))
 11236                    return NavigationSurfaceEdgeAdvanceStatus.Blocked;
 209714237                NavigationConnectionOwnerKey owner = _pendingExplicitOwner;
 209714238                _pendingExplicitOwner = default;
 209714239                _hasPendingExplicitOwner = false;
 209714240                FillExplicit(owner);
 209714241                return TrySelectReadyEdge();
 242            }
 243        }
 244
 929816245        if (!_hasSeam && !_seamComplete)
 246        {
 643083247            if (!_hasPendingSeam)
 248            {
 643082249                if (!_seam.MoveNext())
 440105250                    _seamComplete = true;
 251                else
 252                {
 202977253                    _pendingSeam = _seam.Current;
 202977254                    _hasPendingSeam = true;
 255                }
 256            }
 643083257            if (_hasPendingSeam)
 258            {
 202978259                if (!TryConsumeCandidate(
 202978260                        queryMeter,
 202978261                        maintenanceMeter,
 202978262                        ref guideMeter,
 202978263                        useGuideMeter,
 202978264                        ref edgeStepRemaining))
 1265                    return NavigationSurfaceEdgeAdvanceStatus.Blocked;
 202977266                NavigationAutomaticSeamRef seam = _pendingSeam;
 202977267                _pendingSeam = default;
 202977268                _hasPendingSeam = false;
 202977269                FillSeam(seam);
 202977270                return TrySelectReadyEdge();
 271            }
 272        }
 273
 726838274        return TrySelectReadyEdge();
 275    }
 276
 277    private NavigationSurfaceEdgeAdvanceStatus TrySelectReadyEdge()
 278    {
 1848389279        if (!IsSelectionReady(
 1848389280                _hasNative,
 1848389281                _nativeComplete,
 1848389282                _hasExplicit,
 1848389283                _explicitComplete,
 1848389284                _hasSeam,
 1848389285                _seamComplete))
 286        {
 581688287            return NavigationSurfaceEdgeAdvanceStatus.Pending;
 288        }
 1266701289        if (!_hasNative && !_hasExplicit && !_hasSeam)
 290        {
 224647291            Current = default;
 224647292            return NavigationSurfaceEdgeAdvanceStatus.Complete;
 293        }
 1042054294        NavigationGraphEdge selected = default;
 1042054295        NavigationCellAddress selectedEndpoint = default;
 1042054296        int selectedKind = -1;
 1042054297        if (_hasNative)
 298        {
 777615299            selected = _nativeEdge;
 777615300            selectedEndpoint = _nativeEndpoint;
 777615301            selectedKind = 0;
 302        }
 1042054303        if (_hasExplicit
 1042054304            && (selectedKind < 0
 1042054305                || Compare(
 1042054306                    _explicitEdge,
 1042054307                    _explicitEndpoint,
 1042054308                    selected,
 1042054309                    selectedEndpoint) < 0))
 310        {
 190660311            selected = _explicitEdge;
 190660312            selectedEndpoint = _explicitEndpoint;
 190660313            selectedKind = 1;
 314        }
 1042054315        if (_hasSeam
 1042054316            && (selectedKind < 0
 1042054317                || Compare(
 1042054318                    _seamEdge,
 1042054319                    _seamEndpoint,
 1042054320                    selected,
 1042054321                    selectedEndpoint) < 0))
 322        {
 182786323            selected = _seamEdge;
 182786324            selectedKind = 2;
 325        }
 1042054326        Current = selected;
 1042054327        _currentOrdinal++;
 1042054328        if (selectedKind == 0)
 708773329            _hasNative = false;
 333281330        else if (selectedKind == 1)
 150495331            _hasExplicit = false;
 332        else
 182786333            _hasSeam = false;
 1042054334        return NavigationSurfaceEdgeAdvanceStatus.Edge;
 335    }
 336
 337    internal static bool IsSelectionReady(
 338        bool hasNative,
 339        bool nativeComplete,
 340        bool hasExplicit,
 341        bool explicitComplete,
 342        bool hasSeam,
 1848395343        bool seamComplete) => (hasNative || nativeComplete)
 1848395344        && (hasExplicit || explicitComplete)
 1848395345        && (hasSeam || seamComplete);
 346
 347    private void FillExplicit(NavigationConnectionOwnerKey owner)
 348    {
 209714349        if (!_graph!.ExplicitConnections.TryGet(
 209714350                owner,
 209714351                out NavigationExplicitConnectionRecord record)
 209714352            || !record.IsActive)
 353        {
 213354            return;
 355        }
 356        NavigationCellAddress endpoint;
 209501357        if (_incoming)
 358        {
 37315359            if (!record.Destination.Equals(_origin))
 8651360                return;
 28664361            endpoint = record.Source;
 362        }
 363        else
 364        {
 172186365            if (!record.Source.Equals(_origin))
 33764366                return;
 138422367            endpoint = record.Destination;
 368        }
 167086369        bool found = _graph.TryGetNodeRef(endpoint, out NavigationNodeRef target);
 370        System.Diagnostics.Debug.Assert(found,
 371            "Active explicit endpoints belong to published graph nodes.");
 167086372        _explicitEndpoint = endpoint;
 167086373        _explicitEdge = new NavigationGraphEdge(target, record);
 167086374        _hasExplicit = true;
 167086375    }
 376
 377    private void FillSeam(NavigationAutomaticSeamRef seam)
 378    {
 202977379        NavigationCellAddress endpoint = seam.Destination;
 202977380        bool found = _graph!.TryGetNodeRef(endpoint, out NavigationNodeRef target);
 381        System.Diagnostics.Debug.Assert(found,
 382            "Active automatic-seam rows reference published graph nodes.");
 202977383        bool hasEffectiveCell = false;
 202977384        bool hasNodeState = false;
 202977385        NavigationNodeState state = default;
 202977386        if (_structural)
 2819387            hasEffectiveCell = _graph.HasEffectiveCell(endpoint);
 388        else
 200158389            hasNodeState = _graph.TryGetNodeState(target, out state);
 202977390        if (!IsSeamEndpointEligible(
 202977391                _structural,
 202977392                hasEffectiveCell,
 202977393                hasNodeState,
 202977394                state.IsPresent))
 395        {
 8396            return;
 397        }
 202969398        _seamEndpoint = endpoint;
 202969399        _seamEdge = new NavigationGraphEdge(target, seam);
 202969400        _hasSeam = true;
 202969401    }
 402
 403    internal static bool IsSeamEndpointEligible(
 404        bool structural,
 405        bool hasEffectiveCell,
 406        bool hasNodeState,
 202982407        bool isPresent) => structural
 202982408        ? hasEffectiveCell
 202982409        : hasNodeState && isPresent;
 410
 411    internal static bool TryConsumeCandidate(
 412        NavigationWorkMeter? queryMeter,
 413        MaintenanceWorkMeter? maintenanceMeter,
 414        ref GuideSampleWorkMeter guideMeter,
 415        bool useGuideMeter,
 416        ref int edgeStepRemaining)
 417    {
 491234418        if (queryMeter == null && maintenanceMeter == null && !useGuideMeter)
 360433419            return true;
 130801420        if (edgeStepRemaining == 0
 130801421            || (queryMeter != null && !queryMeter.TryConsumeEvaluatedEdges(1))
 130801422            || (maintenanceMeter != null
 130801423                && !maintenanceMeter.TryConsumeSurfaceComponentEdges(1))
 130801424            || (useGuideMeter && !guideMeter.TryConsumeCursorLegScans(1)))
 425        {
 191426            return false;
 427        }
 130610428        edgeStepRemaining--;
 130610429        return true;
 430    }
 431
 432    private static int Compare(
 433        in NavigationGraphEdge left,
 434        NavigationCellAddress leftEndpoint,
 435        in NavigationGraphEdge right,
 436        NavigationCellAddress rightEndpoint)
 437    {
 316326438        int comparison = leftEndpoint.CompareTo(rightEndpoint);
 316326439        if (comparison != 0)
 162698440            return comparison;
 153628441        comparison = (int)left.Kind - (int)right.Kind;
 153628442        return comparison;
 443    }
 444}