|
H5CPP
v1.14.0
Modern C++ templates for HDF5 serial and parallel I/O
|
|
Dense + sparse linear-algebra container support — Armadillo, Eigen, Blaze, Blitz++, dlib, IT++, Boost uBLAS, xtensor. Eight upstream libraries, one dispatch.
H5CPP recognises linear-algebra containers from eight C++ libraries as first-class template arguments to h5::read, h5::write, and h5::create. Each library is opted in by including a single mapper header — until that include happens, the dispatch leaves the library's types out of storage_representation_v<T> and a call site fails at compile time with a clear diagnostic.
| Library | Mapper header | Dense vectors / matrices | Sparse |
|---|---|---|---|
| Armadillo | h5cpp/H5Marma.hpp | arma::Row<T>, Col<T>, Mat<T>, Cube<T> | arma::SpMat, SpRow, SpCol |
| Eigen | h5cpp/H5Meigen.hpp | Eigen::Matrix<T,R,C,O>, Eigen::Array<T,R,C,O> | Eigen::SparseMatrix, SparseVector (CSC) |
| Blitz++ | h5cpp/H5Mblitz.hpp | blitz::Array<T,N> (rank-N, up to 11) | — |
| Blaze | h5cpp/H5Mblaze.hpp | blaze::DynamicVector<T,O>, DynamicMatrix<T,O> (both orientations) | — |
| dlib | h5cpp/H5Mdlib.hpp | dlib::matrix<T,0,0,...,row_major_layout> | — |
| IT++ | h5cpp/H5Mitpp.hpp | itpp::Vec<T>, Mat<T> | — |
| Boost uBLAS | h5cpp/H5Mublas.hpp | boost::numeric::ublas::vector<T>, matrix<T> | — |
| xtensor | h5cpp/H5Mxtensor.hpp | xt::xarray<T> (dynamic rank), xt::xtensor<T,N> (static rank) | — |
std::valarray (mapper at h5cpp/H5Mvalarray.hpp) follows the same opt-in pattern but lives under STL since it's shipped with the standard library.
Every dense container is a contiguous buffer of T with one pointer (memptr(), data(), valuePtr(), …) into a single heap allocation. h5cpp passes that pointer straight to H5Dwrite/H5Dread with no copy and no transpose, so the on-disk layout matches the upstream container's in-memory layout byte-for-byte.
arma::Row, Eigen::VectorXd, blaze::DynamicVector, ublas::vector, etc. on the same dataset is byte-exact.Matrices (rank-2) inherit the container's storage order:
arma::Mat, Eigen::Matrix<…,ColMajor> (default), blaze::DynamicMatrix<…,columnMajor>.dlib::matrix, Eigen::Matrix<…,RowMajor>, blaze::DynamicMatrix<…,rowMajor>, ublas::matrix (default), itpp::Mat.Reading a column-major dataset into a row-major container does not transpose — it reinterprets, producing the mathematical transpose. Cross-library reads must match orientation.
xt::xarray, xt::xtensor, blitz::Array, arma::Cube) follow the upstream's default storage order.All dense linalg containers resolve to storage_representation_t::linear_value_dataset — the same path std::vector<T> takes.
arma::SpMat / SpRow / SpCol and Eigen::SparseMatrix<T,ColMajor> land as an HDF5 group containing four datasets and two scalar attributes:
Byte-compatible with scipy.sparse.csc_matrix, Julia HDF5.jl, and the 10x Genomics / Loompy on-disk convention.
Preconditions (h5cpp does not call them implicitly — both would require mutating a const &):
arma::SpMat: SpMat::sync() must have completed.Eigen::SparseMatrix: makeCompressed() must have been called; ColMajor is enforced via static_assert (RowMajor refuses at compile time).Multiple mapper headers can be active in the same translation unit. The dispatches are partitioned by type — h5::write(fd, "a", arma_x) and h5::write(fd, "b", eigen_y) co-exist without conflict.
The historical foot-gun is Armadillo's LAPACK wrappers vs Blaze's BLAS path. For mixed arma + blaze code, define BLAZE_BLAS_MODE=0 before including Blaze.
Each mapper header specialises three traits in h5::meta:
is_contiguous<T>** — declares that T::memptr() / data() / valuePtr() returns a pointer to a contiguous buffer of decay<T>::type elements.storage_representation_impl<T>** — pins the value to linear_value_dataset (dense) or routes through is_sparse<T> for sparse.access_traits_t<T>** — exposes the rank, dimensions, and element pointer that H5Dread.hpp / H5Dwrite.hpp consume.Once those three are in scope, the type joins the same generic read/write/create dispatch as std::vector<T> — no per-library special-case at the call site.