< Summary

Information
Class: Trailblazer.Pathing.NavigationQueryAdmissionCoordinator
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/NavigationQueryAdmissionCoordinator.cs
Line coverage
100%
Covered lines: 64
Uncovered lines: 0
Coverable lines: 64
Total lines: 148
Line coverage: 100%
Branch coverage
100%
Covered branches: 20
Total branches: 20
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%11100%
get_ActiveCount()100%11100%
TryReservePrefix(...)100%66100%
Trim(...)100%44100%
Release(...)100%22100%
TryGetActiveLane(...)100%88100%
GetLane(...)100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Search/NavigationQueryAdmissionCoordinator.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationQueryAdmissionCoordinator.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
 8using System;
 9
 10namespace Trailblazer.Pathing;
 11
 12/// <summary>Identifies one generation-safe aggregate query-capacity reservation.</summary>
 13internal readonly struct NavigationQueryCapacityReservation
 14{
 15    internal NavigationQueryCapacityReservation(
 16        NavigationQueryAdmissionCoordinator owner,
 17        int lane,
 18        ulong generation,
 19        int count)
 20    {
 21        Owner = owner;
 22        Lane = lane;
 23        Generation = generation;
 24        Count = count;
 25    }
 26
 27    internal NavigationQueryAdmissionCoordinator? Owner { get; }
 28    internal int Lane { get; }
 29    internal ulong Generation { get; }
 30    internal int Count { get; }
 31}
 32
 33/// <summary>Bounds aggregate A* and Flow admission without sharing their workers.</summary>
 34internal sealed class NavigationQueryAdmissionCoordinator
 35{
 101536    private readonly object _sync = new();
 101537    private readonly LaneState[] _lanes = new LaneState[2];
 38    private readonly int _maximumCount;
 39    private int _activeCount;
 40
 101541    internal NavigationQueryAdmissionCoordinator(int maximumCount)
 42    {
 101543        SwiftThrowHelper.ThrowIfArgumentOutOfRange(
 101544            maximumCount <= 0,
 101545            maximumCount,
 101546            nameof(maximumCount));
 101547        _maximumCount = maximumCount;
 101548    }
 49
 50    internal int ActiveCount
 51    {
 52        get
 53        {
 1654            lock (_sync)
 1655                return _activeCount;
 1656        }
 57    }
 58
 59    internal int TryReservePrefix(
 60        PathAlgorithm algorithm,
 61        int requestedCount,
 62        out NavigationQueryCapacityReservation reservation)
 63    {
 46764        SwiftThrowHelper.ThrowIfNegative(requestedCount, nameof(requestedCount));
 46765        int lane = GetLane(algorithm);
 46766        lock (_sync)
 67        {
 46768            ref LaneState state = ref _lanes[lane];
 46769            int count = Math.Min(requestedCount, _maximumCount - _activeCount);
 46770            if (requestedCount == 0
 46771                || state.Active
 46772                || count == 0)
 73            {
 274                reservation = default;
 275                return 0;
 76            }
 46577            state.Generation = unchecked(state.Generation + 1UL);
 46578            state.Count = count;
 46579            state.Active = true;
 46580            _activeCount += count;
 46581            reservation = new NavigationQueryCapacityReservation(
 46582                this,
 46583                lane,
 46584                state.Generation,
 46585                count);
 46586            return count;
 87        }
 46788    }
 89
 90    internal NavigationQueryCapacityReservation Trim(
 91        NavigationQueryCapacityReservation reservation,
 92        int retainedCount)
 93    {
 87494        lock (_sync)
 95        {
 87496            if (!TryGetActiveLane(reservation, out int lane))
 497                return default;
 87098            ref LaneState state = ref _lanes[lane];
 87099            _activeCount -= state.Count - retainedCount;
 870100            state.Count = retainedCount;
 870101            if (retainedCount == 0)
 102            {
 2103                state.Active = false;
 2104                return default;
 105            }
 868106            return new NavigationQueryCapacityReservation(
 868107                this,
 868108                lane,
 868109                state.Generation,
 868110                retainedCount);
 111        }
 874112    }
 113
 114    internal void Release(NavigationQueryCapacityReservation reservation)
 115    {
 468116        lock (_sync)
 117        {
 468118            if (!TryGetActiveLane(reservation, out int lane))
 5119                return;
 463120            ref LaneState state = ref _lanes[lane];
 463121            _activeCount -= state.Count;
 463122            state.Count = 0;
 463123            state.Active = false;
 463124        }
 468125    }
 126
 127    private bool TryGetActiveLane(
 128        NavigationQueryCapacityReservation reservation,
 129        out int lane)
 130    {
 1342131        lane = reservation.Lane;
 1342132        return ReferenceEquals(reservation.Owner, this)
 1342133            && (uint)lane < (uint)_lanes.Length
 1342134            && _lanes[lane].Active
 1342135            && _lanes[lane].Generation == reservation.Generation
 1342136            && _lanes[lane].Count == reservation.Count;
 137    }
 138
 139    private static int GetLane(PathAlgorithm algorithm) =>
 467140        algorithm == PathAlgorithm.AStar ? 0 : 1;
 141
 142    private struct LaneState
 143    {
 144        internal ulong Generation;
 145        internal int Count;
 146        internal bool Active;
 147    }
 148}