< Summary

Information
Class: GridForge.Spatial.PartitionProvider<T>
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Spatial/PartitionProvider.cs
Line coverage
100%
Covered lines: 119
Uncovered lines: 0
Coverable lines: 119
Total lines: 347
Line coverage: 100%
Branch coverage
100%
Covered branches: 64
Total branches: 64
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_IsEmpty()100%11100%
get_Count()100%22100%
TryAdd(...)100%1010100%
TryRemove(...)100%66100%
TryGet(...)100%66100%
TryGet(...)100%44100%
Has(...)100%11100%
Has()100%11100%
Clear()100%22100%
ClearSecondPartition()100%11100%
TryAddOverflowPartition(...)100%44100%
TryRemoveOverflowPartition(...)100%22100%
TryGetOverflowPartition(...)100%22100%
FindOverflowPartitionIndex(...)100%66100%
MoveFirstOverflowPartitionToSecondSlot()100%44100%
GetEnumerator()100%11100%
.ctor(...)100%66100%
MoveNext()100%1010100%
.ctor(...)100%11100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Spatial/PartitionProvider.cs

#LineLine coverage
 1//=======================================================================
 2// PartitionProvider.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.Runtime.CompilerServices;
 10using SwiftCollections;
 11
 12namespace GridForge.Spatial;
 13
 14/// <summary>
 15/// Provides efficient storage and retrieval of partitions keyed by their exact concrete <see cref="Type"/>.
 16/// </summary>
 17/// <remarks>
 18/// The first two concrete types are stored inline. Additional types use provider-owned overflow
 19/// storage that is cleared and retained after compaction so a later promotion can reuse it.
 20/// Enumeration and compaction preserve registration order.
 21/// </remarks>
 22public sealed class PartitionProvider<TPartitionBase> where TPartitionBase : class
 23{
 24    /// <summary>
 25    /// The first inline partition used by the common one- and two-partition paths.
 26    /// </summary>
 27    private Type? _firstPartitionType;
 28
 29    /// <summary>
 30    /// The first inline partition used by the common one- and two-partition paths.
 31    /// </summary>
 32    private TPartitionBase? _firstPartition;
 33
 34    /// <summary>
 35    /// The second inline partition used by the common two-partition-per-voxel path.
 36    /// </summary>
 37    private Type? _secondPartitionType;
 38
 39    /// <summary>
 40    /// The second inline partition used by the common two-partition-per-voxel path.
 41    /// </summary>
 42    private TPartitionBase? _secondPartition;
 43
 44    /// <summary>
 45    /// Overflow storage used only when a voxel hosts more than two concrete partition types.
 46    /// The dictionary remains owned by the provider after compaction so later promotions can reuse it.
 47    /// </summary>
 48    private SwiftList<OverflowPartition>? _overflowPartitions;
 49
 50    /// <summary>
 51    /// Indicates whether the provider currently contains any partitions.
 52    /// Returns true if empty; otherwise, false.
 53    /// </summary>
 13101254    public bool IsEmpty => _firstPartition == null;
 55
 56    /// <summary>
 57    /// Gets the current number of partitions stored in the provider.
 58    /// </summary>
 59    public int Count =>
 660        (_firstPartition != null ? 1 : 0)
 661        + (_secondPartition != null ? 1 : 0)
 662        + (_overflowPartitions?.Count ?? 0);
 63
 64    /// <summary>
 65    /// Attempts to add a partition to the provider with the specified type key.
 66    /// Returns true if the partition was added; false if a partition with the same type already exists.
 67    /// </summary>
 68    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 69    public bool TryAdd(Type partitionType, TPartitionBase partition)
 70    {
 71        // Both checks are side-effect free; evaluating both avoids an extra hot-path branch.
 9772        if (partitionType == null | partition == null)
 273            return false;
 74
 9575        if (_firstPartition == null)
 76        {
 5677            _firstPartitionType = partitionType;
 5678            _firstPartition = partition;
 5679            return true;
 80        }
 81
 3982        if (_firstPartitionType == partitionType)
 383            return false;
 84
 3685        if (_secondPartition == null)
 86        {
 2587            _secondPartitionType = partitionType;
 2588            _secondPartition = partition;
 2589            return true;
 90        }
 91
 1192        if (_secondPartitionType == partitionType)
 193            return false;
 94
 1095        return TryAddOverflowPartition(partitionType!, partition!);
 96    }
 97
 98    /// <summary>
 99    /// Attempts to remove a partition associated with the specified type.
 100    /// If successful, the removed partition is returned in the out parameter.
 101    /// Returns true if the partition was removed; otherwise, false.
 102    /// </summary>
 103    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 104    public bool TryRemove(Type partitionType, out TPartitionBase? partition)
 105    {
 63106        partition = null;
 107
 63108        if (partitionType == null)
 1109            return false;
 110
 62111        if (_firstPartitionType == partitionType)
 112        {
 40113            partition = _firstPartition;
 40114            _firstPartitionType = _secondPartitionType;
 40115            _firstPartition = _secondPartition;
 40116            ClearSecondPartition();
 40117            MoveFirstOverflowPartitionToSecondSlot();
 40118            return true;
 119        }
 120
 22121        if (_secondPartitionType == partitionType)
 122        {
 17123            partition = _secondPartition;
 17124            ClearSecondPartition();
 17125            MoveFirstOverflowPartitionToSecondSlot();
 17126            return true;
 127        }
 128
 5129        return TryRemoveOverflowPartition(partitionType, out partition);
 130    }
 131
 132    /// <summary>
 133    /// Attempts to retrieve a partition associated with the specified concrete type.
 134    /// </summary>
 135    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 136    public bool TryGet(Type partitionType, out TPartitionBase? partition)
 137    {
 1078138        partition = null;
 139
 1078140        if (partitionType == null)
 1141            return false;
 142
 1077143        if (_firstPartitionType == partitionType)
 144        {
 1052145            partition = _firstPartition;
 1052146            return true;
 147        }
 148
 25149        if (_secondPartitionType == partitionType)
 150        {
 4151            partition = _secondPartition;
 4152            return true;
 153        }
 154
 21155        return TryGetOverflowPartition(partitionType, out partition);
 156    }
 157
 158    /// <summary>
 159    /// Attempts to retrieve a partition of the specified type.
 160    /// Returns true and sets the out parameter if the partition exists and is of the requested type; otherwise, returns
 161    /// </summary>
 162    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 163    public bool TryGet<T>(out T? partition) where T : TPartitionBase
 164    {
 1072165        partition = default;
 166
 1072167        if (!TryGet(typeof(T), out TPartitionBase? tempPartition) || tempPartition is not T typedPartition)
 15168            return false;
 169
 1057170        partition = typedPartition;
 1057171        return true;
 172    }
 173
 174    /// <summary>
 175    /// Determines whether the provider contains a partition associated with the specified concrete type.
 176    /// </summary>
 177    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 178    public bool Has(Type partitionType)
 179    {
 1180        return TryGet(partitionType, out _);
 181    }
 182
 183    /// <summary>
 184    /// Determines whether the provider contains a partition of the specified type.
 185    /// Returns true if such a partition exists; otherwise, false.
 186    /// </summary>
 187    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 188    public bool Has<T>() where T : TPartitionBase
 189    {
 9190        return TryGet<T>(out _);
 191    }
 192
 193    /// <summary>
 194    /// Removes all partitions from the provider, clearing its internal storage.
 195    /// </summary>
 196    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 197    public void Clear()
 198    {
 15199        _firstPartitionType = null;
 15200        _firstPartition = null;
 15201        ClearSecondPartition();
 15202        _overflowPartitions?.Clear();
 5203    }
 204
 205    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 206    private void ClearSecondPartition()
 207    {
 72208        _secondPartitionType = null;
 72209        _secondPartition = null;
 72210    }
 211
 212    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 213    private bool TryAddOverflowPartition(Type partitionType, TPartitionBase partition)
 214    {
 10215        if (FindOverflowPartitionIndex(partitionType) >= 0)
 1216            return false;
 217
 9218        _overflowPartitions ??= new SwiftList<OverflowPartition>(4);
 9219        _overflowPartitions.Add(new OverflowPartition(partitionType, partition));
 9220        return true;
 221    }
 222
 223    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 224    private bool TryRemoveOverflowPartition(Type partitionType, out TPartitionBase? partition)
 225    {
 5226        int index = FindOverflowPartitionIndex(partitionType);
 5227        if (index < 0)
 228        {
 3229            partition = null;
 3230            return false;
 231        }
 232
 2233        partition = _overflowPartitions!.InnerArray[index].Partition;
 2234        _overflowPartitions.RemoveAt(index);
 2235        return true;
 236    }
 237
 238    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 239    private bool TryGetOverflowPartition(Type partitionType, out TPartitionBase? partition)
 240    {
 21241        int index = FindOverflowPartitionIndex(partitionType);
 21242        if (index < 0)
 243        {
 19244            partition = null;
 19245            return false;
 246        }
 247
 2248        partition = _overflowPartitions!.InnerArray[index].Partition;
 2249        return true;
 250    }
 251
 252    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 253    private int FindOverflowPartitionIndex(Type partitionType)
 254    {
 36255        if (_overflowPartitions == null)
 19256            return -1;
 257
 17258        OverflowPartition[] partitions = _overflowPartitions.InnerArray;
 46259        for (int i = 0; i < _overflowPartitions.Count; i++)
 260        {
 11261            if (partitions[i].Type == partitionType)
 5262                return i;
 263        }
 264
 12265        return -1;
 266    }
 267
 268    private void MoveFirstOverflowPartitionToSecondSlot()
 269    {
 57270        if (_overflowPartitions == null || _overflowPartitions.Count == 0)
 55271            return;
 272
 2273        OverflowPartition overflowPartition = _overflowPartitions[0];
 2274        _overflowPartitions.RemoveAt(0);
 2275        _secondPartitionType = overflowPartition.Type;
 2276        _secondPartition = overflowPartition.Partition;
 2277    }
 278
 279    /// <summary>
 280    /// Returns an allocation-free enumerator for the provider's current partitions.
 281    /// </summary>
 282    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 18283    internal Enumerator GetEnumerator() => new(this);
 284
 285    internal struct Enumerator
 286    {
 287        private readonly TPartitionBase? _firstPartition;
 288        private readonly TPartitionBase? _secondPartition;
 289        private readonly bool _hasOverflow;
 290        private SwiftList<OverflowPartition>.SwiftListEnumerator _overflowEnumerator;
 291        private int _inlineState;
 292
 293        internal Enumerator(PartitionProvider<TPartitionBase> provider)
 294        {
 18295            _firstPartition = provider._firstPartition;
 18296            _secondPartition = provider._secondPartition;
 18297            _overflowEnumerator = provider._overflowPartitions != null
 18298                ? provider._overflowPartitions.GetEnumerator()
 18299                : default;
 18300            _hasOverflow = provider._overflowPartitions != null
 18301                && provider._overflowPartitions.Count > 0;
 18302            _inlineState = _firstPartition != null ? 0 : 2;
 18303            Current = default!;
 18304        }
 305
 306        public TPartitionBase Current { get; private set; }
 307
 308        public bool MoveNext()
 309        {
 48310            if (_inlineState == 0)
 311            {
 17312                Current = _firstPartition!;
 17313                _inlineState = 1;
 17314                return true;
 315            }
 316
 31317            if (_inlineState == 1)
 318            {
 17319                _inlineState = 2;
 17320                if (_secondPartition != null)
 321                {
 6322                    Current = _secondPartition;
 6323                    return true;
 324                }
 325            }
 326
 25327            if (!_hasOverflow || !_overflowEnumerator.MoveNext())
 18328                return false;
 329
 7330            Current = _overflowEnumerator.Current.Partition;
 7331            return true;
 332        }
 333    }
 334
 335    private readonly struct OverflowPartition
 336    {
 337        internal OverflowPartition(Type type, TPartitionBase partition)
 338        {
 9339            Type = type;
 9340            Partition = partition;
 9341        }
 342
 343        internal Type Type { get; }
 344
 345        internal TPartitionBase Partition { get; }
 346    }
 347}