< Summary

Information
Class: GridForge.Grids.Storage.SparseVoxelBlock
Assembly: GridForge
File(s): /home/runner/work/GridForge/GridForge/src/GridForge/Grids/Storage/SparseVoxelBlock.cs
Line coverage
100%
Covered lines: 101
Uncovered lines: 0
Coverable lines: 101
Total lines: 204
Line coverage: 100%
Branch coverage
100%
Covered branches: 52
Total branches: 52
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_Count()100%11100%
Initialize(...)100%22100%
AddPreparedVoxel(...)100%11100%
TryAddVoxel(...)100%44100%
TryRemoveVoxel(...)100%44100%
TryGetVoxel(...)100%22100%
TryFindVoxelArrayIndex(...)100%88100%
EnsureCapacity(...)100%88100%
CreateVoxel(...)100%11100%
AddVoxelsInIndexRange(...)100%88100%
Reset(...)100%66100%
Clear()100%11100%
IsIndexInRange(...)100%1010100%

File(s)

/home/runner/work/GridForge/GridForge/src/GridForge/Grids/Storage/SparseVoxelBlock.cs

#LineLine coverage
 1//=======================================================================
 2// SparseVoxelBlock.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.Buffers;
 10using System.Runtime.CompilerServices;
 11using GridForge.Spatial;
 12using SwiftCollections;
 13
 14namespace GridForge.Grids.Storage;
 15
 16internal sealed class SparseVoxelBlock
 17{
 18    public int CellKey { get; private set; } = -1;
 19
 20    public ScanCell? ScanCell { get; private set; }
 21
 1622    public int Count => _count;
 23
 24    private Voxel[]? _voxels;
 25    private int _count;
 26
 27    public void Initialize(VoxelGrid grid, int cellKey, int capacity)
 28    {
 9029        CellKey = cellKey;
 9030        ScanCell = Pools.ScanCellPool.Rent();
 9031        ScanCell.Initialize(grid, cellKey);
 9032        _voxels = capacity > 0
 9033            ? ArrayPool<Voxel>.Shared.Rent(capacity)
 9034            : null;
 9035        _count = 0;
 9036    }
 37
 38    public Voxel AddPreparedVoxel(VoxelGrid grid, VoxelIndex index)
 39    {
 40        // GridWorld validates prepared sparse input as sorted and deduplicated before storage initialization.
 10441        EnsureCapacity(_count + 1);
 10442        Voxel voxel = CreateVoxel(grid, index);
 10443        _voxels![_count++] = voxel;
 10444        return voxel;
 45    }
 46
 47    public bool TryAddVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 48    {
 4049        voxel = null;
 4050        if (TryFindVoxelArrayIndex(index, out int insertIndex))
 251            return false;
 52
 3853        EnsureCapacity(_count + 1);
 3854        voxel = CreateVoxel(grid, index);
 55
 3856        if (insertIndex < _count)
 1057            Array.Copy(_voxels!, insertIndex, _voxels!, insertIndex + 1, _count - insertIndex);
 58
 3859        _voxels![insertIndex] = voxel;
 3860        _count++;
 3861        return true;
 62    }
 63
 64    public bool TryRemoveVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 65    {
 1766        voxel = null;
 1767        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 368            return false;
 69
 1470        voxel = _voxels![voxelArrayIndex];
 1471        int moveCount = _count - voxelArrayIndex - 1;
 1472        if (moveCount > 0)
 273            Array.Copy(_voxels, voxelArrayIndex + 1, _voxels, voxelArrayIndex, moveCount);
 74
 1475        _voxels[--_count] = null!;
 1476        voxel.Reset(grid);
 1477        Pools.VoxelPool.Release(voxel);
 1478        return true;
 79    }
 80
 81    public bool TryGetVoxel(VoxelIndex index, out Voxel? result)
 82    {
 19383        result = null;
 19384        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 6085            return false;
 86
 13387        result = _voxels![voxelArrayIndex];
 13388        return result.IsAllocated;
 89    }
 90
 91    private bool TryFindVoxelArrayIndex(VoxelIndex index, out int voxelArrayIndex)
 92    {
 25093        voxelArrayIndex = 0;
 25094        if (_voxels == null)
 395            return false;
 96
 24797        int min = 0;
 24798        int max = _count - 1;
 44499        while (min <= max)
 100        {
 346101            int mid = min + ((max - min) >> 1);
 346102            Voxel voxel = _voxels[mid];
 346103            int compare = voxel.Index.CompareTo(index);
 104
 346105            if (compare == 0)
 106            {
 149107                voxelArrayIndex = mid;
 149108                return true;
 109            }
 110
 197111            if (compare < 0)
 146112                min = mid + 1;
 113            else
 51114                max = mid - 1;
 115        }
 116
 98117        voxelArrayIndex = min;
 98118        return false;
 119    }
 120
 121    private void EnsureCapacity(int minCapacity)
 122    {
 142123        if (_voxels != null && _voxels.Length >= minCapacity)
 140124            return;
 125
 2126        int capacity = _voxels == null
 2127            ? minCapacity
 2128            : Math.Max(minCapacity, _voxels.Length << 1);
 2129        Voxel[] replacement = ArrayPool<Voxel>.Shared.Rent(capacity);
 130
 2131        if (_voxels != null)
 132        {
 1133            Array.Copy(_voxels, replacement, _count);
 1134            ArrayPool<Voxel>.Shared.Return(_voxels, clearArray: true);
 135        }
 136
 2137        _voxels = replacement;
 2138    }
 139
 140    private Voxel CreateVoxel(VoxelGrid grid, VoxelIndex index)
 141    {
 142142        Voxel voxel = Pools.VoxelPool.Rent();
 142143        voxel.Initialize(
 142144            new WorldVoxelIndex(grid.World!.SpawnToken, grid.GridIndex, grid.SpawnToken, index),
 142145            grid.GetWorldPosition(index),
 142146            CellKey,
 142147            grid.IsOnBoundary(index),
 142148            grid.Version);
 149
 142150        return voxel;
 151    }
 152
 153    public void AddVoxelsInIndexRange(
 154        VoxelIndex min,
 155        VoxelIndex max,
 156        SwiftList<Voxel> results,
 157        SwiftHashSet<Voxel> redundancy)
 158    {
 44159        if (_voxels == null)
 1160            return;
 161
 188162        for (int i = 0; i < _count; i++)
 163        {
 51164            Voxel voxel = _voxels[i];
 51165            VoxelIndex index = voxel.Index;
 51166            if (IsIndexInRange(index, min, max) && redundancy.Add(voxel))
 43167                results.Add(voxel);
 168        }
 43169    }
 170
 171    public void Reset(VoxelGrid grid)
 172    {
 91173        if (_voxels != null)
 174        {
 436175            for (int i = 0; i < _count; i++)
 176            {
 128177                Voxel voxel = _voxels[i];
 128178                voxel.Reset(grid);
 128179                Pools.VoxelPool.Release(voxel);
 180            }
 181
 90182            ArrayPool<Voxel>.Shared.Return(_voxels, clearArray: true);
 183        }
 184
 91185        if (ScanCell != null)
 90186            Pools.ScanCellPool.Release(ScanCell);
 187
 91188        Clear();
 91189    }
 190
 191    public void Clear()
 192    {
 180193        CellKey = -1;
 180194        ScanCell = null;
 180195        _voxels = null;
 180196        _count = 0;
 180197    }
 198
 199    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 200    private static bool IsIndexInRange(VoxelIndex index, VoxelIndex min, VoxelIndex max) =>
 51201        index.x >= min.x && index.x <= max.x
 51202        && index.y >= min.y && index.y <= max.y
 51203        && index.z >= min.z && index.z <= max.z;
 204}