Back to sparse_spatial_hash

Documentation

API reference and core concepts for sparse_spatial_hash.

API Documentation

The sparse_spatial_hash library provides a high-performance spatial indexing data structure for C++20. It divides space into a grid of cells and uses a hash map to store only occupied cells, making it memory-efficient for large, sparse worlds.

Core Classes

grid_config<N>

Configuration structure for spatial grids.

FieldTypeDescription
cell_sizestd::array<float, N>Size of each cell in each dimension
world_sizestd::array<float, N>Total world size in each dimension
topology_typetopologyBoundary behavior (bounded, toroidal, infinite)
grid_config<3> cfg{
    .cell_size = {10.0f, 10.0f, 10.0f},
    .world_size = {1000.0f, 1000.0f, 1000.0f},
    .topology_type = topology::bounded
};

sparse_spatial_hash<Entity, N>

The main grid class for spatial indexing.

Template Parameters:

ParameterDescription
EntityYour entity type (e.g., Particle, GameObject)
NNumber of dimensions (typically 2 or 3)
FloatFloating-point type (default: float)
IndexIndex type (default: std::size_t)
HashCell hash function (default: cell_hash<N>)
AllocatorAllocator type (default: std::allocator)

position_accessor<Entity, N>

Trait for extracting position from your entity type.

template<>
struct spatial::position_accessor<Particle, 3> {
    static float get(const Particle& p, std::size_t dim) {
        switch(dim) {
            case 0: return p.x;
            case 1: return p.y;
            case 2: return p.z;
            default: return 0.0f;
        }
    }
};

Note: If your entity stores position as std::array<float, N>, the default implementation works automatically.

Topology Types

TypeBehaviorUse Case
topology::boundedCoordinates clamped to [0, world_size]Rooms, arenas, bounded worlds
topology::toroidalCoordinates wrap around (periodic)N-body simulations, Pac-Man-style worlds
topology::infiniteNo bounds checking, grid growsProcedural worlds, expanding universes

Core Operations

Building the Grid

MethodComplexityDescription
rebuild(entities)O(n)Full rebuild from entity container
update(entities)O(k)Incremental update (k = entities that changed cells)
clear()O(1)Remove all entities

Querying

MethodDescription
query_radius(r, x, y, z)Returns indices of entities in cells intersecting query sphere
query_cell(cx, cy, cz)Returns indices of entities in specific cell
for_each_pair(entities, radius, callback)Invokes callback for all pairs within radius

Important: query_radius returns candidates - entities in cells that intersect the query sphere. Always filter by exact distance for precision:

auto candidates = grid.query_radius(radius, x, y, z);
for (auto idx : candidates) {
    float dist = compute_distance(entities[idx], query_point);
    if (dist < radius) {
        // True neighbor
    }
}

Statistics

MethodDescription
entity_count()Total entities in grid
cell_count()Number of occupied cells
stats()Returns grid_stats with detailed metrics
auto stats = grid.stats();
// stats.occupied_cells
// stats.avg_entities_per_cell
// stats.occupancy_ratio
// stats.max_entities_in_cell

Performance Characteristics

OperationComplexityTypical Performance
BuildO(n)14.7M entities/second
Incremental UpdateO(k)29.2M entities/second
Query RadiusO(cells × entities/cell)Sub-microsecond for typical queries
For Each PairO(n × avg_neighbors)Optimized for collision detection

Memory Usage

  • Sparse storage: Only occupied cells use memory
  • Typical: 100MB for 10M particles in 10000³ world
  • Comparison: 60,000× less memory than equivalent dense grid

Full Reference

For complete API documentation with all method signatures and complexity guarantees: