< 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
 1822    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    {
 10429        CellKey = cellKey;
 10430        ScanCell = Pools.ScanCellPool.Rent();
 10431        ScanCell.Initialize(grid, cellKey);
 10432        _voxels = capacity > 0
 10433            ? ArrayPool<Voxel>.Shared.Rent(capacity)
 10434            : null;
 10435        _count = 0;
 10436    }
 37
 38    public Voxel AddPreparedVoxel(VoxelGrid grid, VoxelIndex index)
 39    {
 40        // GridWorld validates prepared sparse input as sorted and deduplicated before storage initialization.
 13741        EnsureCapacity(_count + 1);
 13742        Voxel voxel = CreateVoxel(grid, index);
 13743        _voxels![_count++] = voxel;
 13744        return voxel;
 45    }
 46
 47    public bool TryAddVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 48    {
 4449        voxel = null;
 4450        if (TryFindVoxelArrayIndex(index, out int insertIndex))
 251            return false;
 52
 4253        EnsureCapacity(_count + 1);
 4254        voxel = CreateVoxel(grid, index);
 55
 4256        if (insertIndex < _count)
 1057            Array.Copy(_voxels!, insertIndex, _voxels!, insertIndex + 1, _count - insertIndex);
 58
 4259        _voxels![insertIndex] = voxel;
 4260        _count++;
 4261        return true;
 62    }
 63
 64    public bool TryRemoveVoxel(VoxelGrid grid, VoxelIndex index, out Voxel? voxel)
 65    {
 1966        voxel = null;
 1967        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 368            return false;
 69
 1670        voxel = _voxels![voxelArrayIndex];
 1671        int moveCount = _count - voxelArrayIndex - 1;
 1672        if (moveCount > 0)
 373            Array.Copy(_voxels, voxelArrayIndex + 1, _voxels, voxelArrayIndex, moveCount);
 74
 1675        _voxels[--_count] = null!;
 1676        voxel.Reset(grid);
 1677        Pools.VoxelPool.Release(voxel);
 1678        return true;
 79    }
 80
 81    public bool TryGetVoxel(VoxelIndex index, out Voxel? result)
 82    {
 27383        result = null;
 27384        if (!TryFindVoxelArrayIndex(index, out int voxelArrayIndex))
 6985            return false;
 86
 20487        result = _voxels![voxelArrayIndex];
 20488        return result.IsAllocated;
 89    }
 90
 91    private bool TryFindVoxelArrayIndex(VoxelIndex index, out int voxelArrayIndex)
 92    {
 33693        voxelArrayIndex = 0;
 33694        if (_voxels == null)
 395            return false;
 96
 33397        int min = 0;
 33398        int max = _count - 1;
 62499        while (min <= max)
 100        {
 513101            int mid = min + ((max - min) >> 1);
 513102            Voxel voxel = _voxels[mid];
 513103            int compare = voxel.Index.CompareTo(index);
 104
 513105            if (compare == 0)
 106            {
 222107                voxelArrayIndex = mid;
 222108                return true;
 109            }
 110
 291111            if (compare < 0)
 205112                min = mid + 1;
 113            else
 86114                max = mid - 1;
 115        }
 116
 111117        voxelArrayIndex = min;
 111118        return false;
 119    }
 120
 121    private void EnsureCapacity(int minCapacity)
 122    {
 179123        if (_voxels != null && _voxels.Length >= minCapacity)
 177124            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    {
 179142        Voxel voxel = Pools.VoxelPool.Rent();
 179143        voxel.Initialize(
 179144            new WorldVoxelIndex(grid.World!.SpawnToken, grid.GridIndex, grid.SpawnToken, index),
 179145            grid.GetWorldPosition(index),
 179146            CellKey,
 179147            grid.IsOnBoundary(index),
 179148            grid.Version);
 149
 179150        return voxel;
 151    }
 152
 153    public void AddVoxelsInIndexRange(
 154        VoxelIndex min,
 155        VoxelIndex max,
 156        SwiftList<Voxel> results,
 157        SwiftHashSet<Voxel> redundancy)
 158    {
 50159        if (_voxels == null)
 1160            return;
 161
 220162        for (int i = 0; i < _count; i++)
 163        {
 61164            Voxel voxel = _voxels[i];
 61165            VoxelIndex index = voxel.Index;
 61166            if (IsIndexInRange(index, min, max) && redundancy.Add(voxel))
 53167                results.Add(voxel);
 168        }
 49169    }
 170
 171    public void Reset(VoxelGrid grid)
 172    {
 105173        if (_voxels != null)
 174        {
 534175            for (int i = 0; i < _count; i++)
 176            {
 163177                Voxel voxel = _voxels[i];
 163178                voxel.Reset(grid);
 163179                Pools.VoxelPool.Release(voxel);
 180            }
 181
 104182            ArrayPool<Voxel>.Shared.Return(_voxels, clearArray: true);
 183        }
 184
 105185        if (ScanCell != null)
 104186            Pools.ScanCellPool.Release(ScanCell);
 187
 105188        Clear();
 105189    }
 190
 191    public void Clear()
 192    {
 208193        CellKey = -1;
 208194        ScanCell = null;
 208195        _voxels = null;
 208196        _count = 0;
 208197    }
 198
 199    [MethodImpl(MethodImplOptions.AggressiveInlining)]
 200    private static bool IsIndexInRange(VoxelIndex index, VoxelIndex min, VoxelIndex max) =>
 61201        index.x >= min.x && index.x <= max.x
 61202        && index.y >= min.y && index.y <= max.y
 61203        && index.z >= min.z && index.z <= max.z;
 204}