< 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
98%
Covered branches: 51
Total branches: 52
Branch coverage: 98%
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(...)87.5%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 GridForge.Spatial;
 9using SwiftCollections;
 10using System;
 11using System.Buffers;
 12using System.Runtime.CompilerServices;
 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
 1522    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    {
 7029        CellKey = cellKey;
 7030        ScanCell = Pools.ScanCellPool.Rent();
 7031        ScanCell.Initialize(grid.World!, grid.GridIndex, cellKey);
 7032        _voxels = capacity > 0
 7033            ? ArrayPool<Voxel>.Shared.Rent(capacity)
 7034            : null;
 7035        _count = 0;
 7036    }
 37
 38    public Voxel AddPreparedVoxel(VoxelGrid grid, VoxelIndex index)
 39    {
 40        // GridWorld validates prepared sparse input as sorted and deduplicated before storage initialization.
 8341        EnsureCapacity(_count + 1);
 8342        Voxel voxel = CreateVoxel(grid, index);
 8343        _voxels![_count++] = voxel;
 8344        return voxel;
 45    }
 46
 47    public bool TryAddVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 48    {
 3749        voxel = null;
 3750        if (TryFindVoxelArrayIndex(index, out int insertIndex))
 251            return false;
 52
 3553        EnsureCapacity(_count + 1);
 3554        voxel = CreateVoxel(grid, index);
 55
 3556        if (insertIndex < _count)
 1057            Array.Copy(_voxels!, insertIndex, _voxels!, insertIndex + 1, _count - insertIndex);
 58
 3559        _voxels![insertIndex] = voxel;
 3560        _count++;
 3561        return true;
 62    }
 63
 64    public bool TryRemoveVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 65    {
 1666        voxel = null;
 1667        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 368            return false;
 69
 1370        voxel = _voxels![voxelArrayIndex];
 1371        int moveCount = _count - voxelArrayIndex - 1;
 1372        if (moveCount > 0)
 173            Array.Copy(_voxels, voxelArrayIndex + 1, _voxels, voxelArrayIndex, moveCount);
 74
 1375        _voxels[--_count] = null!;
 1376        voxel.Reset(grid);
 1377        Pools.VoxelPool.Release(voxel);
 1378        return true;
 79    }
 80
 81    public bool TryGetVoxel(VoxelIndex index, out Voxel? result)
 82    {
 15083        result = null;
 15084        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 6185            return false;
 86
 8987        result = _voxels![voxelArrayIndex];
 8988        return result.IsAllocated;
 89    }
 90
 91    private bool TryFindVoxelArrayIndex(VoxelIndex index, out int voxelArrayIndex)
 92    {
 20393        voxelArrayIndex = 0;
 20394        if (_voxels == null)
 395            return false;
 96
 20097        int min = 0;
 20098        int max = _count - 1;
 39599        while (min <= max)
 100        {
 299101            int mid = min + ((max - min) >> 1);
 299102            Voxel voxel = _voxels[mid];
 299103            int compare = voxel.Index.CompareTo(index);
 104
 299105            if (compare == 0)
 106            {
 104107                voxelArrayIndex = mid;
 104108                return true;
 109            }
 110
 195111            if (compare < 0)
 143112                min = mid + 1;
 113            else
 52114                max = mid - 1;
 115        }
 116
 96117        voxelArrayIndex = min;
 96118        return false;
 119    }
 120
 121    private void EnsureCapacity(int minCapacity)
 122    {
 118123        if (_voxels != null && _voxels.Length >= minCapacity)
 116124            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    {
 118142        Voxel voxel = Pools.VoxelPool.Rent();
 118143        voxel.Initialize(
 118144            new WorldVoxelIndex(grid.World!.SpawnToken, grid.GridIndex, grid.SpawnToken, index),
 118145            grid.GetWorldPosition(index),
 118146            CellKey,
 118147            grid.IsOnBoundary(index),
 118148            grid.Version);
 149
 118150        return voxel;
 151    }
 152
 153    public void AddVoxelsInIndexRange(
 154        VoxelIndex min,
 155        VoxelIndex max,
 156        SwiftList<Voxel> results,
 157        SwiftHashSet<Voxel> redundancy)
 158    {
 11159        if (_voxels == null)
 1160            return;
 161
 46162        for (int i = 0; i < _count; i++)
 163        {
 13164            Voxel voxel = _voxels[i];
 13165            VoxelIndex index = voxel.Index;
 13166            if (IsIndexInRange(index, min, max) && redundancy.Add(voxel))
 10167                results.Add(voxel);
 168        }
 10169    }
 170
 171    public void Reset(VoxelGrid grid)
 172    {
 71173        if (_voxels != null)
 174        {
 350175            for (int i = 0; i < _count; i++)
 176            {
 105177                Voxel voxel = _voxels[i];
 105178                voxel.Reset(grid);
 105179                Pools.VoxelPool.Release(voxel);
 180            }
 181
 70182            ArrayPool<Voxel>.Shared.Return(_voxels, clearArray: true);
 183        }
 184
 71185        if (ScanCell != null)
 70186            Pools.ScanCellPool.Release(ScanCell);
 187
 71188        Clear();
 71189    }
 190
 191    public void Clear()
 192    {
 140193        CellKey = -1;
 140194        ScanCell = null;
 140195        _voxels = null;
 140196        _count = 0;
 140197    }
 198
 199    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 200    private static bool IsIndexInRange(VoxelIndex index, VoxelIndex min, VoxelIndex max) =>
 13201        index.x >= min.x && index.x <= max.x
 13202        && index.y >= min.y && index.y <= max.y
 13203        && index.z >= min.z && index.z <= max.z;
 204}