< Summary

Information
Class: Trailblazer.Pathing.NavigationAreaCatalog
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Graph/NavigationAreaCatalog.cs
Line coverage
100%
Covered lines: 72
Uncovered lines: 0
Coverable lines: 72
Total lines: 150
Line coverage: 100%
Branch coverage
100%
Covered branches: 36
Total branches: 36
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%
get_RetainedBytes()100%11100%
get_PersistentPageCount()100%11100%
GetPublishWork(...)100%66100%
TryGet(...)100%44100%
TryPublish(...)100%1818100%
FindPolicy(...)100%66100%

File(s)

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

#LineLine coverage
 1//=======================================================================
 2// NavigationAreaCatalog.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>Stores one immutable, ordinally indexed set of latest area-policy revisions.</summary>
 13internal sealed class NavigationAreaCatalog
 14{
 15    private readonly NavigationAreaPolicy[] _policies;
 16    private readonly long _retainedBytes;
 17
 72018    private NavigationAreaCatalog(NavigationAreaPolicy[] policies, int totalRuleCount, long version)
 19    {
 72020        _policies = policies;
 72021        TotalRuleCount = totalRuleCount;
 72022        Version = version;
 72023        long bytes = 48L + ((long)_policies.Length * sizeof(long));
 288824        for (int i = 0; i < _policies.Length; i++)
 72425            bytes = checked(bytes + _policies[i].RetainedBytes);
 72026        _retainedBytes = bytes;
 72027    }
 28
 29    internal static NavigationAreaCatalog Empty { get; } = new(
 30        Array.Empty<NavigationAreaPolicy>(),
 31        totalRuleCount: 0,
 32        version: 0);
 33
 34    internal int TotalRuleCount { get; }
 35
 36    internal long Version { get; }
 37
 472938    internal long RetainedBytes => _retainedBytes;
 39
 472740    internal int PersistentPageCount => 1 + _policies.Length;
 41
 42    internal int GetPublishWork(
 43        NavigationAreaPolicy policy,
 44        int maxPolicies,
 45        int maxRules)
 46    {
 18847        int index = FindPolicy(policy.Key.PolicyId);
 18848        bool canInsert = index < 0
 18849            && _policies.Length < maxPolicies
 18850            && TotalRuleCount <= maxRules - policy.RuleCount;
 18851        int copiedPolicyReferences = canInsert
 18852            ? _policies.Length + 1
 18853            : _policies.Length;
 18854        return checked(
 18855            1 + Math.Max(policy.RuleCount, 2 * copiedPolicyReferences));
 56    }
 57
 58    internal bool TryGet(NavigationAreaPolicyKey key, out NavigationAreaPolicy policy)
 59    {
 2836560        int index = FindPolicy(key.PolicyId);
 2836561        if (index >= 0 && _policies[index].Key.Equals(key))
 62        {
 2834863            policy = _policies[index];
 2834864            return true;
 65        }
 1766        policy = null!;
 1767        return false;
 68    }
 69
 70    internal NavigationOperationRejection TryPublish(
 71        NavigationAreaPolicy policy,
 72        int maxPolicies,
 73        int requiredRuleCount,
 74        int maxRulesPerPolicy,
 75        int maxRules,
 76        out NavigationAreaCatalog next)
 77    {
 73278        if (policy.RuleCount != requiredRuleCount)
 79        {
 180            next = this;
 181            return NavigationOperationRejection.ValidationFailed;
 82        }
 73183        if (policy.RuleCount > maxRulesPerPolicy)
 84        {
 185            next = this;
 186            return NavigationOperationRejection.CapacityExceeded;
 87        }
 88
 73089        int index = FindPolicy(policy.Key.PolicyId);
 73090        if (index >= 0)
 91        {
 1392            NavigationAreaPolicy current = _policies[index];
 1393            if (policy.Key.Revision < current.Key.Revision)
 94            {
 195                next = this;
 196                return NavigationOperationRejection.Stale;
 97            }
 1298            if (policy.Key.Revision == current.Key.Revision)
 99            {
 8100                next = this;
 8101                return current.ContentEquals(policy)
 8102                    ? NavigationOperationRejection.None
 8103                    : NavigationOperationRejection.ValidationFailed;
 104            }
 105
 4106            int rules = checked(TotalRuleCount - current.RuleCount + policy.RuleCount);
 4107            if (rules > maxRules)
 108            {
 1109                next = this;
 1110                return NavigationOperationRejection.CapacityExceeded;
 111            }
 3112            var replacement = (NavigationAreaPolicy[])_policies.Clone();
 3113            replacement[index] = policy;
 3114            next = new NavigationAreaCatalog(replacement, rules, Version + 1);
 3115            return NavigationOperationRejection.None;
 116        }
 117
 717118        if (_policies.Length >= maxPolicies || TotalRuleCount + policy.RuleCount > maxRules)
 119        {
 1120            next = this;
 1121            return NavigationOperationRejection.CapacityExceeded;
 122        }
 123
 716124        int insertion = ~index;
 716125        var added = new NavigationAreaPolicy[_policies.Length + 1];
 716126        Array.Copy(_policies, 0, added, 0, insertion);
 716127        added[insertion] = policy;
 716128        Array.Copy(_policies, insertion, added, insertion + 1, _policies.Length - insertion);
 716129        next = new NavigationAreaCatalog(added, TotalRuleCount + policy.RuleCount, Version + 1);
 716130        return NavigationOperationRejection.None;
 131    }
 132
 133    private int FindPolicy(string policyId)
 134    {
 29283135        int low = 0;
 29283136        int high = _policies.Length - 1;
 29295137        while (low <= high)
 138        {
 28391139            int middle = low + ((high - low) >> 1);
 28391140            int comparison = string.CompareOrdinal(_policies[middle].Key.PolicyId, policyId);
 28391141            if (comparison == 0)
 28379142                return middle;
 12143            if (comparison < 0)
 7144                low = middle + 1;
 145            else
 5146                high = middle - 1;
 147        }
 904148        return ~low;
 149    }
 150}