![]() |
ImFusion C++ SDK 4.5.0
|
#include <ImFusion/Core/SparseArray.h>
A sparse paged array for memory-efficient storage of sparse data. More...
A sparse paged array for memory-efficient storage of sparse data.
SparseArray implements a two-level sparse array structure that only allocates memory for blocks that contain non-zero values. This is particularly useful for histogram computations, label remapping, or any scenario where you have a large index space but only a small fraction of indices are actually used.
This data structure was designed to replace std::unordered_map for integer-keyed sparse arrays, avoiding hash collision overhead and providing more predictable performance characteristics.
The data structure divides the index space into fixed-size blocks (pages). Blocks are only allocated on-demand when an element within that block is first accessed. This provides:
Memory Complexity:
For N non-zero elements with maximum index M:
Usage Examples:
Performance Considerations:
| T | The value type to store (e.g., uint32_t for counts, uint16_t for labels). Must be a valid non-type template parameter (integral, enum, or pointer type). |
| BlockSize | The number of elements per block. Larger blocks reduce pointer indirection overhead but may waste more memory for very sparse data. |
| Sentinel | The value treated as "not present". Defaults to T{} (zero for numeric types). Use a different value if you need zero as a valid stored value, e.g., -1 for signed types. |
Public Member Functions | |
| SparseArray ()=default | |
| Default constructor. Creates an empty sparse array. | |
| ~SparseArray ()=default | |
| Destructor. Automatically frees all allocated blocks. | |
| SparseArray (const SparseArray &)=delete | |
| Non-copyable. Use explicit copy or move semantics if needed. | |
| SparseArray & | operator= (const SparseArray &)=delete |
| Non-copyable. Use explicit copy or move semantics if needed. | |
| SparseArray (SparseArray &&other) noexcept=default | |
| Move constructor. Transfers ownership of blocks. | |
| SparseArray & | operator= (SparseArray &&other) noexcept=default |
| Move assignment. Transfers ownership of blocks. | |
| T & | operator[] (size_t index) |
| Mutable element access with automatic block allocation. | |
| const T & | operator[] (size_t index) const noexcept |
| Read-only element access without allocation. | |
| const T & | get (size_t index) const noexcept |
| Read-only element access without allocation (convenience for non-const objects). | |
| template<typename Func> | |
| void | forEachNonZero (Func &&callback) const |
| Iterate over all non-sentinel entries in the sparse array. | |
| void | clear () noexcept |
| Clear all allocated blocks and free memory. | |
| size_t | allocatedBlocks () const noexcept |
| Get the number of allocated blocks. | |
| size_t | capacity () const noexcept |
| Get the maximum index that could be addressed without reallocation. | |
|
inline |
Mutable element access with automatic block allocation.
Returns a reference to the element at the specified index. If the block containing this index doesn't exist, it will be allocated and zero-initialized.
|
inlinenoexcept |
Read-only element access without allocation.
Returns a const reference to the element at the specified index. If the block containing this index doesn't exist, returns a reference to the sentinel value.
|
inlinenoexcept |
Read-only element access without allocation (convenience for non-const objects).
Equivalent to std::as_const(*this)[index]. Prefer this over operator[] when you only need to read a value and want to avoid block allocation.
|
inline |
Iterate over all non-sentinel entries in the sparse array.
Efficiently iterates only over allocated blocks and non-sentinel values within them. The callback is invoked with (index, value) for each non-sentinel entry.
| Func | Callable with signature void(size_t index, T value) or compatible |
|
inlinenoexcept |
Clear all allocated blocks and free memory.
After calling clear(), the sparse array is empty and all memory is freed. The object can still be reused for new insertions.
|
inlinenoexcept |
Get the number of allocated blocks.
This is useful for diagnostics or memory usage estimation. Actual memory usage ≈ allocatedBlocks() * BlockSize * sizeof(T)