< Summary

Information
Class: Trailblazer.Pathing.NavigationMapOverlayDelta
Assembly: Trailblazer
File(s): /home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/Overlay/NavigationMapOverlayDelta.cs
Line coverage
100%
Covered lines: 133
Uncovered lines: 0
Coverable lines: 133
Total lines: 251
Line coverage: 100%
Branch coverage
100%
Covered branches: 44
Total branches: 44
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.cctor()100%11100%
.ctor(...)100%44100%
get_Cells()100%11100%
get_Connections()100%11100%
get_Transitions()100%11100%
get_CellSpan()100%11100%
get_ConnectionSpan()100%11100%
get_TransitionSpan()100%11100%
ValidateCells(...)100%1818100%
ValidateConnections(...)100%66100%
ValidateConnectionWitnesses(...)100%22100%
ValidateTransitions(...)100%44100%
EstimateDescriptorBytes()100%11100%
EstimateRetainedPayload(...)100%11100%
EstimateIdOperations(...)100%22100%
EstimateIdOperations(...)100%22100%
EstimateRetainedPayload(...)100%44100%
EstimateRetainedPayload(...)100%22100%
Compare(...)100%11100%
Compare(...)100%11100%
Compare(...)100%11100%

File(s)

/home/runner/work/Trailblazer/Trailblazer/src/Trailblazer/Pathing/Map/Overlay/NavigationMapOverlayDelta.cs

#LineLine coverage
 1//=======================================================================
 2// NavigationMapOverlayDelta.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;
 9using System.Collections.Generic;
 10using System.Collections.ObjectModel;
 11using SwiftCollections;
 12
 13namespace Trailblazer.Pathing;
 14
 15/// <summary>
 16/// Contains the canonically ordered semantic overlay operations for one source map.
 17/// </summary>
 18public sealed class NavigationMapOverlayDelta
 19{
 120    private static readonly IComparer<NavigationCellOverlayOperation> CellComparer = new CellOperationComparer();
 121    private static readonly IComparer<NavigationConnectionOverlayOperation> ConnectionComparer = new ConnectionOperation
 122    private static readonly IComparer<TraversalTransitionOverlayOperation> TransitionComparer = new TransitionOperationC
 23
 24    private readonly NavigationCellOverlayOperation[] _cells;
 25    private readonly NavigationConnectionOverlayOperation[] _connections;
 26    private readonly TraversalTransitionOverlayOperation[] _transitions;
 27    private readonly ReadOnlyCollection<NavigationCellOverlayOperation> _cellView;
 28    private readonly ReadOnlyCollection<NavigationConnectionOverlayOperation> _connectionView;
 29    private readonly ReadOnlyCollection<TraversalTransitionOverlayOperation> _transitionView;
 30
 31    /// <summary>
 32    /// Initializes an immutable delta and normalizes every operation collection into canonical key order.
 33    /// </summary>
 41234    public NavigationMapOverlayDelta(
 41235        string mapId,
 41236        ReadOnlySpan<NavigationCellOverlayOperation> cells = default,
 41237        ReadOnlySpan<NavigationConnectionOverlayOperation> connections = default,
 41238        ReadOnlySpan<TraversalTransitionOverlayOperation> transitions = default)
 39    {
 41240        SwiftThrowHelper.ThrowIfNull(mapId, nameof(mapId));
 41241        SwiftThrowHelper.ThrowIfArgument(
 41242            string.IsNullOrWhiteSpace(mapId),
 41243            nameof(mapId),
 41244            "Map id cannot be empty or whitespace.");
 41245        SwiftThrowHelper.ThrowIfArgument(
 41246            cells.IsEmpty && connections.IsEmpty && transitions.IsEmpty,
 41247            nameof(cells),
 41248            "A map overlay delta must contain at least one operation.");
 49
 41250        MapId = mapId;
 41251        _cells = cells.ToArray();
 41252        _connections = connections.ToArray();
 41253        _transitions = transitions.ToArray();
 54
 41255        Array.Sort(_cells, CellComparer);
 41256        Array.Sort(_connections, ConnectionComparer);
 41257        Array.Sort(_transitions, TransitionComparer);
 58
 41259        ValidateCells(_cells);
 41060        ValidateConnections(_connections);
 41061        ValidateTransitions(_transitions);
 41062        _cellView = Array.AsReadOnly(_cells);
 41063        _connectionView = Array.AsReadOnly(_connections);
 41064        _transitionView = Array.AsReadOnly(_transitions);
 41065        EstimatedDescriptorBytes = EstimateDescriptorBytes();
 41066    }
 67
 68    /// <summary>Gets the stable source map identifier.</summary>
 69    public string MapId { get; }
 70
 71    /// <summary>Gets canonically ordered, unique cell operations.</summary>
 6831872    public IReadOnlyList<NavigationCellOverlayOperation> Cells => _cellView;
 73
 74    /// <summary>Gets canonically ordered, unique connection operations.</summary>
 882375    public IReadOnlyList<NavigationConnectionOverlayOperation> Connections => _connectionView;
 76
 77    /// <summary>Gets canonically ordered, unique transition operations.</summary>
 877278    public IReadOnlyList<TraversalTransitionOverlayOperation> Transitions => _transitionView;
 79
 5100780    internal ReadOnlySpan<NavigationCellOverlayOperation> CellSpan => _cells;
 81
 94382    internal ReadOnlySpan<NavigationConnectionOverlayOperation> ConnectionSpan => _connections;
 83
 56784    internal ReadOnlySpan<TraversalTransitionOverlayOperation> TransitionSpan => _transitions;
 85
 86    /// <summary>
 87    /// Gets a deterministic conservative byte count for admission of this submitted descriptor.
 88    /// It is not the retained runtime-overlay size.
 89    /// </summary>
 90    public long EstimatedDescriptorBytes { get; }
 91
 92    private static void ValidateCells(NavigationCellOverlayOperation[] operations)
 93    {
 3549694        for (int i = 0; i < operations.Length; i++)
 95        {
 1733896            NavigationCell cell = operations[i].Cell;
 1733897            SwiftThrowHelper.ThrowIfArgument(
 1733898                operations[i].Kind == NavigationCellOverlayOperationKind.Set
 1733899                && (cell.Media == TraversalMedia.None
 17338100                    || (cell.Media & ~NavigationCell.KnownMedia) != 0
 17338101                    || (cell.RequiredCapabilities & ~NavigationCell.KnownCapabilities) != 0
 17338102                    || cell.EnterCost < FixedMathSharp.Fixed64.Zero
 17338103                    || cell.RadiusClearance < FixedMathSharp.Fixed64.Zero
 17338104                    || cell.HeightClearance < FixedMathSharp.Fixed64.Zero
 17338105                    || (cell.Flags & ~NavigationCell.KnownFlags) != 0),
 17338106                nameof(operations),
 17338107                "Cell Set requires one complete valid navigation-cell payload.");
 17337108            SwiftThrowHelper.ThrowIfArgument(
 17337109                i > 0 && operations[i - 1].Index.CompareTo(operations[i].Index) == 0,
 17337110                nameof(operations),
 17337111                "Cell overlay addresses must be unique.");
 112        }
 410113    }
 114
 115    private static void ValidateConnections(NavigationConnectionOverlayOperation[] operations)
 116    {
 9152117        for (int i = 0; i < operations.Length; i++)
 118        {
 4166119            NavigationConnectionOverlayOperation operation = operations[i];
 4166120            SwiftThrowHelper.ThrowIfArgument(
 4166121                string.IsNullOrWhiteSpace(operation.Id),
 4166122                nameof(operations),
 4166123                "Connection overlay ids cannot be empty.");
 4166124            if (operation.Kind == NavigationConnectionOverlayOperationKind.Upsert)
 125            {
 4147126                ValidateConnectionWitnesses(operation.Connection!, operations);
 127            }
 4166128            SwiftThrowHelper.ThrowIfArgument(
 4166129                i > 0 && string.Equals(operations[i - 1].Id, operations[i].Id, StringComparison.Ordinal),
 4166130                nameof(operations),
 4166131                "Connection overlay ids must be unique.");
 132        }
 410133    }
 134
 135    private static void ValidateConnectionWitnesses(
 136        NavigationConnection connection,
 137        NavigationConnectionOverlayOperation[] operations)
 138    {
 4147139        var witnesses = new SwiftHashSet<NavigationCellAddress>(connection.Witnesses.Count);
 8860140        for (int witness = 0; witness < connection.Witnesses.Count; witness++)
 141        {
 283142            SwiftThrowHelper.ThrowIfArgument(
 283143                string.IsNullOrWhiteSpace(connection.Witnesses[witness].MapId),
 283144                nameof(operations),
 283145                "Connection witness map ids cannot be empty.");
 283146            SwiftThrowHelper.ThrowIfArgument(
 283147                !witnesses.Add(connection.Witnesses[witness]),
 283148                nameof(operations),
 283149                "Connection witnesses must be unique.");
 150        }
 4147151    }
 152
 153    private static void ValidateTransitions(TraversalTransitionOverlayOperation[] operations)
 154    {
 9062155        for (int i = 0; i < operations.Length; i++)
 156        {
 4121157            SwiftThrowHelper.ThrowIfArgument(
 4121158                string.IsNullOrWhiteSpace(operations[i].Id),
 4121159                nameof(operations),
 4121160                "Transition overlay ids cannot be empty.");
 4121161            SwiftThrowHelper.ThrowIfArgument(
 4121162                i > 0 && string.Equals(operations[i - 1].Id, operations[i].Id, StringComparison.Ordinal),
 4121163                nameof(operations),
 4121164                "Transition overlay ids must be unique.");
 165        }
 410166    }
 167
 168    private long EstimateDescriptorBytes()
 169    {
 410170        long bytes = NavigationByteCount.SaturatingAdd(
 410171            32L,
 410172            (long)MapId.Length * sizeof(char));
 410173        bytes = NavigationByteCount.SaturatingAdd(bytes, (long)_cells.Length * 64L);
 410174        bytes = NavigationByteCount.SaturatingAdd(bytes, EstimateIdOperations(_connections));
 410175        return NavigationByteCount.SaturatingAdd(bytes, EstimateIdOperations(_transitions));
 176    }
 177
 17325178    internal static long EstimateRetainedPayload(NavigationCellOverlayOperation operation) => 64L;
 179
 180    private static long EstimateIdOperations(NavigationConnectionOverlayOperation[] operations)
 181    {
 410182        long bytes = 0;
 9152183        for (int i = 0; i < operations.Length; i++)
 4166184            bytes = NavigationByteCount.SaturatingAdd(bytes, EstimateRetainedPayload(operations[i]));
 410185        return bytes;
 186    }
 187
 188    private static long EstimateIdOperations(TraversalTransitionOverlayOperation[] operations)
 189    {
 410190        long bytes = 0;
 9062191        for (int i = 0; i < operations.Length; i++)
 4121192            bytes = NavigationByteCount.SaturatingAdd(bytes, EstimateRetainedPayload(operations[i]));
 410193        return bytes;
 194    }
 195
 196    internal static long EstimateRetainedPayload(NavigationConnectionOverlayOperation operation)
 197    {
 8352198        long bytes = NavigationByteCount.SaturatingAdd(
 8352199            96L,
 8352200            (long)operation.Id.Length * sizeof(char));
 8352201        if (operation.Kind != NavigationConnectionOverlayOperationKind.Upsert)
 37202            return bytes;
 203
 8315204        NavigationConnection connection = operation.Connection!;
 8315205        bytes = NavigationByteCount.SaturatingAdd(bytes, 96L);
 8315206        bytes = NavigationByteCount.SaturatingAdd(
 8315207            bytes,
 8315208            (long)connection.Destination.MapId.Length * sizeof(char));
 17794209        for (int witness = 0; witness < connection.Witnesses.Count; witness++)
 210        {
 582211            bytes = NavigationByteCount.SaturatingAdd(bytes, 32L);
 582212            bytes = NavigationByteCount.SaturatingAdd(
 582213                bytes,
 582214                (long)connection.Witnesses[witness].MapId.Length * sizeof(char));
 215        }
 8315216        return bytes;
 217    }
 218
 219    internal static long EstimateRetainedPayload(TraversalTransitionOverlayOperation operation)
 220    {
 8254221        long bytes = NavigationByteCount.SaturatingAdd(
 8254222            96L,
 8254223            (long)operation.Id.Length * sizeof(char));
 8254224        if (operation.Kind == TraversalTransitionOverlayOperationKind.Upsert)
 225        {
 8235226            bytes = NavigationByteCount.SaturatingAdd(bytes, 64L);
 8235227            bytes = NavigationByteCount.SaturatingAdd(
 8235228                bytes,
 8235229                (long)operation.Transition.Destination.MapId.Length * sizeof(char));
 230        }
 8254231        return bytes;
 232    }
 233
 234    private sealed class CellOperationComparer : IComparer<NavigationCellOverlayOperation>
 235    {
 236        public int Compare(NavigationCellOverlayOperation left, NavigationCellOverlayOperation right) =>
 149754237            left.Index.CompareTo(right.Index);
 238    }
 239
 240    private sealed class ConnectionOperationComparer : IComparer<NavigationConnectionOverlayOperation>
 241    {
 242        public int Compare(NavigationConnectionOverlayOperation left, NavigationConnectionOverlayOperation right) =>
 28443243            string.CompareOrdinal(left.Id, right.Id);
 244    }
 245
 246    private sealed class TransitionOperationComparer : IComparer<TraversalTransitionOverlayOperation>
 247    {
 248        public int Compare(TraversalTransitionOverlayOperation left, TraversalTransitionOverlayOperation right) =>
 28448249            string.CompareOrdinal(left.Id, right.Id);
 250    }
 251}

Methods/Properties

.cctor()
.ctor(System.String,System.ReadOnlySpan`1<Trailblazer.Pathing.NavigationCellOverlayOperation>,System.ReadOnlySpan`1<Trailblazer.Pathing.NavigationConnectionOverlayOperation>,System.ReadOnlySpan`1<Trailblazer.Pathing.TraversalTransitionOverlayOperation>)
get_Cells()
get_Connections()
get_Transitions()
get_CellSpan()
get_ConnectionSpan()
get_TransitionSpan()
ValidateCells(Trailblazer.Pathing.NavigationCellOverlayOperation[])
ValidateConnections(Trailblazer.Pathing.NavigationConnectionOverlayOperation[])
ValidateConnectionWitnesses(Trailblazer.Pathing.NavigationConnection,Trailblazer.Pathing.NavigationConnectionOverlayOperation[])
ValidateTransitions(Trailblazer.Pathing.TraversalTransitionOverlayOperation[])
EstimateDescriptorBytes()
EstimateRetainedPayload(Trailblazer.Pathing.NavigationCellOverlayOperation)
EstimateIdOperations(Trailblazer.Pathing.NavigationConnectionOverlayOperation[])
EstimateIdOperations(Trailblazer.Pathing.TraversalTransitionOverlayOperation[])
EstimateRetainedPayload(Trailblazer.Pathing.NavigationConnectionOverlayOperation)
EstimateRetainedPayload(Trailblazer.Pathing.TraversalTransitionOverlayOperation)
Compare(Trailblazer.Pathing.NavigationCellOverlayOperation,Trailblazer.Pathing.NavigationCellOverlayOperation)
Compare(Trailblazer.Pathing.NavigationConnectionOverlayOperation,Trailblazer.Pathing.NavigationConnectionOverlayOperation)
Compare(Trailblazer.Pathing.TraversalTransitionOverlayOperation,Trailblazer.Pathing.TraversalTransitionOverlayOperation)