|
H5CPP
v1.14.0
Modern C++ templates for HDF5 serial and parallel I/O
|
|
A full coverage matrix for every STL container shape supported by h5cpp's dispatch — sourced from the Write-Side / Read-Side Type Matrices in tasks/h5cpp-type-system-architecture-notes.md.
Each family lives in its own translation unit so the failure surface stays narrow:
Every round-trip prints the read-back through h5cpp's STL pretty-printer (operator<< overloads from H5Uall.hpp) and verifies the result with the project's symbol convention:
| Symbol | Meaning |
|---|---|
| ✔ ok | round-trip succeeded, value preserved |
| ✘ failed | round-trip ran but value diverged |
| ◇ na | path blocked by a known library bug; documented below |
| Family | Type | Kind | Storage | Status |
|---|---|---|---|---|
| sequences | std::vector<T> | contiguous | linear_value_dataset | ✔ ok |
std::array<T, N> | contiguous | linear_value_dataset | ✔ ok | |
std::list<T> | iterators | linear_value_dataset | ✔ ok | |
std::deque<T> | iterators | linear_value_dataset | ✔ ok | |
std::forward_list<T> | iterators | linear_value_dataset | ✔ ok | |
T[N] (C-array) | contiguous | c_array | ✔ ok | |
| sets | std::set<T> | iterators | linear_value_dataset | ✔ ok |
std::multiset<T> | iterators | linear_value_dataset | ✔ ok | |
std::unordered_set<T> | iterators | linear_value_dataset | ✔ ok | |
std::unordered_multiset<T> | iterators | linear_value_dataset | ✔ ok | |
| maps | std::map<K, V> | iterators | key_value_dataset | ✔ ok |
std::multimap<K, V> | iterators | key_value_dataset | ✔ ok | |
std::unordered_map<K, V> | iterators | key_value_dataset | ✔ ok | |
std::unordered_multimap<K, V> | iterators | key_value_dataset | ✔ ok | |
| strings | std::string (scalar) | text | vlen_text_dataset | ✔ ok |
std::string_view (scalar) | text | vlen_text_dataset | ✔ ok | |
char[N] (fixed length) | text | fixed_length_string | ✔ ok | |
std::array<char, N> (fixed length) | text | fixed_length_string | ✔ ok | |
std::vector<std::array<char, N>> | contiguous | fls_dataset | ✔ ok | |
std::vector<std::string> | pointers | vlen_text_dataset | ✔ ok | |
| tuples / pairs | std::tuple<arith, arith, ...> (scalar) | composite | scalar | ✔ ok |
std::tuple<..., std::string, ...> (scalar) | composite | scalar | ◇ na | |
std::vector<std::tuple<...>> | pointers | linear_value_dataset | ✔ ok | |
std::list<std::tuple<...>> | iterators | linear_value_dataset | ✔ ok | |
std::pair<K, V> (scalar) | object | scalar | ✔ ok | |
std::vector<std::pair<K, V>> | contiguous | linear_value_dataset | ✔ ok | |
| nested / numeric | std::vector<std::vector<T>> | pointers | ragged_vlen_dataset | ✔ ok |
std::vector<std::list<T>> | pointers | ragged_vlen_dataset | ✔ ok | |
std::vector<std::deque<T>> | pointers | ragged_vlen_dataset | ✔ ok | |
std::vector<std::set<T>> | pointers | ragged_vlen_dataset | ✔ ok | |
std::vector<std::forward_list<T>> | pointers | ragged_vlen_dataset | ✔ ok | |
std::vector<std::array<T, N>> (non-char T) | contiguous | array_dataset (H5T_ARRAY elem) | ✔ ok | |
std::list<std::array<T, N>> / set / deque / forward_list (non-char T) | iterators | array_dataset (iter-staged) | ✔ ok | |
std::array<std::array<T, N>, M> (nested) | contiguous | array_element (nested H5T_ARRAY) | ✔ ok | |
std::complex<T> (scalar) | object | scalar | ✔ ok | |
std::vector<std::complex<T>> | contiguous | linear_value_dataset | ✔ ok | |
| compound (POD) | std::vector<sn::example::Record> | pointers | linear_value_dataset | ✔ ok |
31 / 32 paths verified ✔ ok; the only ◇ na is std::tuple with a std::string field — separate from the library bugs since it's a layout-representation mismatch (std::string is 24-byte object vs HDF5's 8-byte vlen char* slot).
(Set / unordered_set / unordered_map element order varies on read-back — the verification helpers in sets.cpp / maps.cpp use multiset-style comparison for those types.)
| Type family | Use the by-reference read | Why |
|---|---|---|
std::string scalar | yes | Return-style read<std::string>(fd, path) lands in the vlen_text vector branch and fails to compile. |
std::pair<K,V> scalar | yes | Return-style read<std::pair<...>>(fd, path) lands in the contiguous branch, which expects impl::data(pair). |
std::complex<T> scalar | yes | Same as pair — the return-style read lands in a branch missing impl::data(complex). |
| everything else | either form is fine | Both auto v = h5::read<T>(fd, path) and T v; h5::read(fd, path, v) work. |
The scalar paths above also have library-level bugs that prevent them from working even with the by-reference form (see the next section).
std::tuple with std::string fieldsThe HDF5 compound type advertises an 8-byte vlen-string slot at offset O, but the in-memory std::tuple layout has the full 24-byte std::string object at that offset. tuple_layout::to_buffer is a straight memcpy of each field, which dumps the std::string's pointer/size/capacity triple into HDF5's vlen-string slot — UB on disk.
A real fix requires per-field pack/unpack that converts string members to const char* on the way down and back to std::string on the way up — a non-trivial refactor of tuple_layout. The same constraint applies to vector<tuple<..., string, ...>>. The path is left ◇ na for a future pass.
These are documented in the arch notes as unsupported; the static_assert stopper fires at compile time before any HDF5 call. They are NOT broken — they are the design boundary.
| Type | Stopper message |
|---|---|
std::vector<bool> | ‘storage_representation_v<T> resolved to 'unsupported’\ilinebr </td> </tr> <tr class="markdownTableRowEven"> <td class="markdownTableBodyNone">std::vector<std::list<T>>,std::list<std::list<T>>, etc. \ilinebr </td> <td class="markdownTableBodyNone">containers of containers are only supported for vector<string> (vlen_text_dataset) or vector<vector<T>> (ragged_vlen_dataset)\ilinebr </td> </tr> <tr class="markdownTableRowOdd"> <td class="markdownTableBodyNone">std::array<std::string, N>,std::array<std::vector<T>, N>\ilinebr </td> <td class="markdownTableBodyNone">storage_representation_v<T> resolved to 'unsupported'(array-of-container guard) \ilinebr </td> </tr> <tr class="markdownTableRowEven"> <td class="markdownTableBodyNone"> Unregistered POD struct \ilinebr </td> <td class="markdownTableBodyNone">storage_representation_v<T> resolved to 'unsupported'` — Check: unregistered POD aggregate (use H5CPP_REGISTER_STRUCT) |
To see one fire, uncomment a h5::write(fd, "/v", std::vector<bool>{1,0,1}); line — the compile error names the offending type and points at H5Dwrite.hpp (and the equivalent in the other three dispatch headers).
Container output uses the operator<< overloads from H5Uall.hpp. Format conventions:
| Container shape | Renders as |
|---|---|
iterable (vector, list, set, ...) | [a,b,c,d,...] |
std::pair<K, V> | {k:v} |
std::tuple<Ts...> | <v0,v1,...,vN> |
std::map<K, V> (and friends) | [{k1:v1},{k2:v2},...] |
| stack / queue adaptors | [top,...,bottom] (non-destructive) |
Long containers truncate at H5CPP_CONSOLE_WIDTH (default 10, this build uses 30) with a trailing ", ...". See examples/pprint/README.md for the full inserter story.
tasks/h5cpp-type-system-architecture-notes.md** — the source of truth for the dispatch matrix (Section "Complete Write-Side Type Matrix" / "Complete Read-Side Type Matrix").examples/pprint/** — focused demo of the operator<< inserters used by every verification line here.examples/compound/** — the single-file version of the compound POD path that compound.cpp reuses.examples/container/** — the same I/O dispatch surface for STL and custom (non-std::) containers.h5cpp/H5Mstl.hpp** — the per-container access-traits specialisations.compound.cpp — rendered with syntax highlightinggenerated.h — rendered with syntax highlightingmaps.cpp — rendered with syntax highlightingnested.cpp — rendered with syntax highlightingsequences.cpp — rendered with syntax highlightingsets.cpp — rendered with syntax highlightingstrings.cpp — rendered with syntax highlightingstruct.h — rendered with syntax highlightingtuples_pairs.cpp — rendered with syntax highlighting