Skip to content

Commit 5fbf4cf

Browse files
steven-vargasteven varga
authored andcommitted
Merge remote-tracking branch 'origin/267-swmr-support' into staging
# Conflicts: # h5cpp/H5Dappend.hpp # h5cpp/H5Fcreate.hpp
2 parents 7245c57 + 1a78eec commit 5fbf4cf

25 files changed

Lines changed: 1172 additions & 895 deletions

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ jobs:
184184
tar -xzf $zlib_archive -C $env:RUNNER_TEMP
185185
186186
cmake -S $zlib_source -B $zlib_build `
187-
-G "Visual Studio 17 2022" -A x64 `
187+
-G "Visual Studio 18 2026" -A x64 `
188188
-DCMAKE_INSTALL_PREFIX="$zlib_prefix"
189189
cmake --build $zlib_build --parallel --config Release
190190
cmake --install $zlib_build --config Release
@@ -218,7 +218,7 @@ jobs:
218218
tar -xzf $hdf5_archive -C $env:RUNNER_TEMP
219219
220220
cmake -S $hdf5_source -B $hdf5_build `
221-
-G "Visual Studio 17 2022" `
221+
-G "Visual Studio 18 2026" `
222222
-A x64 `
223223
-DCMAKE_INSTALL_PREFIX="$hdf5_prefix" `
224224
-DHDF_CFG_NAME=Release `

.github/workflows/package.yml

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ on:
99
permissions:
1010
contents: write
1111

12+
env:
13+
HDF5_SERIES: "1.12"
14+
HDF5_VERSION: 1.12.3
15+
HDF5_CACHE_VERSION: v5
16+
1217
concurrency:
1318
group: package-${{ github.ref }}
1419
cancel-in-progress: true
@@ -38,14 +43,20 @@ jobs:
3843
run: |
3944
sudo apt-get update -qq
4045
sudo apt-get install -y --no-install-recommends \
41-
libhdf5-dev rpm
46+
cmake ninja-build wget rpm
47+
48+
- name: Install HDF5 ${{ env.HDF5_VERSION }} from source
49+
uses: ./.github/actions/install-hdf5
50+
with:
51+
cache-key-suffix: -pkg-${{ matrix.arch }}
4252

4353
- name: Configure
4454
run: |
4555
cmake -B build \
4656
-DCMAKE_BUILD_TYPE=Release \
4757
-DCMAKE_INSTALL_PREFIX=/usr \
4858
-DCPACK_PACKAGING_INSTALL_PREFIX=/usr \
59+
-DHDF5_ROOT="$HDF5_ROOT" \
4960
-DH5CPP_BUILD_EXAMPLES=OFF \
5061
-DH5CPP_BUILD_TESTS=OFF \
5162
-DH5CPP_BUILD_BENCH=OFF \
@@ -125,10 +136,7 @@ jobs:
125136
# cached between runs.
126137
package-windows:
127138
name: windows / x64 / NSIS
128-
runs-on: windows-latest
129-
env:
130-
HDF5_VERSION: 1.12.2
131-
HDF5_CACHE_VERSION: v3
139+
runs-on: windows-2025-vs2026
132140

133141
steps:
134142
- uses: actions/checkout@v4
@@ -168,7 +176,7 @@ jobs:
168176
tar -xzf $zlib_archive -C $env:RUNNER_TEMP
169177
170178
cmake -S $zlib_source -B $zlib_build `
171-
-G "Visual Studio 17 2022" -A x64 `
179+
-G "Visual Studio 18 2026" -A x64 `
172180
-DCMAKE_INSTALL_PREFIX="$zlib_prefix"
173181
cmake --build $zlib_build --parallel --config Release
174182
cmake --install $zlib_build --config Release
@@ -178,7 +186,7 @@ jobs:
178186
uses: actions/cache/restore@v5
179187
with:
180188
path: ${{ runner.temp }}\hdf5-${{ env.HDF5_VERSION }}-install
181-
key: hdf5-windows-vs2022-${{ env.HDF5_VERSION }}-pkg-${{ env.HDF5_CACHE_VERSION }}
189+
key: hdf5-${{ runner.os }}-pkg-${{ env.HDF5_VERSION }}-${{ env.HDF5_CACHE_VERSION }}
182190

183191
- name: Build HDF5 from source
184192
if: steps.cache-hdf5.outputs.cache-hit != 'true'
@@ -197,7 +205,7 @@ jobs:
197205
tar -xzf $hdf5_archive -C $env:RUNNER_TEMP
198206
199207
cmake -S $hdf5_source -B $hdf5_build `
200-
-G "Visual Studio 17 2022" -A x64 `
208+
-G "Visual Studio 18 2026" -A x64 `
201209
-DCMAKE_INSTALL_PREFIX="$hdf5_prefix" `
202210
-DHDF_CFG_NAME=Release `
203211
-DBUILD_SHARED_LIBS=ON `

CMakeLists.txt

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ endif()
1616
# embeds it as PROJECT_VERSION rather than a stale hardcoded number. Falls
1717
# back to a placeholder when building from a tarball without git history.
1818
find_package(Git QUIET)
19-
set(H5CPP_PROJECT_VERSION "1.12.7")
19+
set(H5CPP_PROJECT_VERSION "1.14.0")
2020
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
2121
execute_process(
2222
COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0 --match "v[0-9]*"
@@ -158,6 +158,26 @@ else()
158158
message(STATUS "H5CPP: ROS3 VFD not found — S3 support disabled")
159159
endif()
160160

161+
# ─── SWMR (Single-Writer/Multiple-Reader) — issue #267 ────────────────────────────
162+
# Single-Writer/Multiple-Reader support is Linux-only in this release and requires
163+
# HDF5 >= 1.12.3 (the patch level mitigates the pre-1.14 dense-attribute SWMR
164+
# visibility bug; see SWMR.md §8.5). The runtime feature gate inside the headers
165+
# keys on the HDF5 feature macros (H5F_ACC_SWMR_WRITE / H5F_ACC_SWMR_READ),
166+
# mirroring the ROS3-v2 FAPL gating pattern — NOT on H5_VERSION_GE. CMake's job
167+
# here is only to (a) hard-fail when the HDF5 floor is too low on a Linux build
168+
# that pulls SWMR headers, and (b) surface an informational status line.
169+
set(H5CPP_SWMR_HDF5_FLOOR "1.12.3")
170+
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
171+
if(HDF5_VERSION VERSION_LESS ${H5CPP_SWMR_HDF5_FLOOR})
172+
message(FATAL_ERROR
173+
"h5cpp SWMR (#267) requires HDF5 >= ${H5CPP_SWMR_HDF5_FLOOR}, found ${HDF5_VERSION}")
174+
endif()
175+
set(H5CPP_HAS_SWMR TRUE)
176+
message(STATUS "H5CPP: SWMR support enabled (Linux, HDF5 ${HDF5_VERSION})")
177+
else()
178+
message(STATUS "H5CPP: SWMR support disabled (Linux-only; CMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME})")
179+
endif()
180+
161181
option(H5CPP_NETWORK_TESTS "Enable network-dependent tests (requires outbound S3 access)" OFF)
162182

163183
# ─── MPI (optional) ───────────────────────────────────────────────────────────────
@@ -220,8 +240,7 @@ target_include_directories(h5cpp INTERFACE $<BUILD_INTERFACE:${H5CPP_INCLUDE_DI
220240
target_link_libraries(h5cpp INTERFACE ${H5CPP_LIBS})
221241
target_compile_features(h5cpp INTERFACE cxx_std_20)
222242

223-
# MSVC does not update __cplusplus to reflect the actual standard without this flag;
224-
# without it the #error guard in H5Qall.hpp always fires even under /std:c++20.
243+
# MSVC does not update __cplusplus to reflect the actual standard without this flag.
225244
if(MSVC)
226245
target_compile_options(h5cpp INTERFACE /Zc:__cplusplus)
227246
endif()
@@ -254,6 +273,13 @@ if(H5CPP_HAVE_ROS3_VFD)
254273
target_compile_definitions(h5cpp INTERFACE H5CPP_HAVE_ROS3_VFD=1)
255274
endif()
256275

276+
# SWMR build flag (#267) — only set on Linux with a recent-enough HDF5. The
277+
# header-only feature gate (H5CPP_HAS_SWMR) additionally keys on the HDF5
278+
# feature macros, so this define alone does not force the feature on.
279+
if(H5CPP_HAS_SWMR)
280+
target_compile_definitions(h5cpp INTERFACE H5CPP_SWMR_BUILD=1)
281+
endif()
282+
257283
if(H5CPP_LIBDEFLATE_FOUND)
258284
target_link_libraries(h5cpp INTERFACE ${H5CPP_LIBDEFLATE_TARGET})
259285
target_compile_definitions(h5cpp INTERFACE H5CPP_HAS_LIBDEFLATE=1)

README.md

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# H5CPP
12
[![CI](https://github.com/vargalabs/h5cpp/actions/workflows/ci.yml/badge.svg)](https://github.com/vargalabs/h5cpp/actions/workflows/ci.yml)
23
[![ASan](https://vargalabs.github.io/h5cpp/badges/asan.svg)](https://github.com/vargalabs/h5cpp/actions/workflows/ci.yml)
34
[![UBSan](https://vargalabs.github.io/h5cpp/badges/ubsan.svg)](https://github.com/vargalabs/h5cpp/actions/workflows/ci.yml)
@@ -7,7 +8,16 @@
78
[![GitHub release](https://img.shields.io/github/v/release/vargalabs/h5cpp.svg)](https://github.com/vargalabs/h5cpp/releases)
89
[![Documentation](https://img.shields.io/badge/docs-stable-blue)](https://vargalabs.github.io/h5cpp)
910

10-
# H5CPP — High-Performance [HDF5][hdf5] for Modern C++
11+
Modern C++ for HDF5
12+
--------------------
13+
**H5CPP** is a modern C++ template library for serial and parallel HDF5 I/O. It provides type-safe RAII wrappers, high-level `create` / `read` / `write` / `append` operations, and seamless interoperability with the native HDF5 C API. Chunked and compressed datasets, extendable packet-table streams, hyperslab selection, custom datatypes, and MPI parallel I/O are all supported. HDF5 files written by H5CPP are readable from Python, R, MATLAB, Fortran, Julia, and any other HDF5-capable environment.
14+
15+
| Layer | Role |
16+
|---|---|
17+
| **H5CPP** | Header-only C++ HDF5 I/O library |
18+
| [h5cpp-compiler][compiler] | Optional build-time reflection tool for non-POD struct persistence |
19+
20+
## Supported platforms
1121

1222
| OS / Compiler | GCC 13 | GCC 14 | GCC 15 | Clang 17 | Clang 18 | Clang 19 | Clang 20 | Apple Clang | MSVC |
1323
|---------------|---------------|---------------|-----------|--------------|--------------|--------------|--------------|-------------|--------------|
@@ -16,22 +26,31 @@
1626
| macOS 15 | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![ac][400] | ![NA][NA] |
1727
| Windows | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![NA][NA] | ![msvc][500] |
1828

19-
H5CPP is a modern C++ template library for serial and parallel HDF5 I/O. It provides type-safe RAII wrappers, high-level `create` / `read` / `write` / `append` operations, and seamless interoperability with the native HDF5 C API. Chunked and compressed datasets, extendable packet-table streams, hyperslab selection, custom datatypes, and MPI parallel I/O are all supported. HDF5 files written by H5CPP are readable from Python, R, MATLAB, Fortran, Julia, and any other HDF5-capable environment.
20-
2129
## Quick Start
2230

2331
```cpp
2432
#include <h5cpp/all>
2533
#include <vector>
2634

35+
namespace sn::sensor {
36+
struct [[h5::doc("Time-series sensor reading with variable-length fields"),
37+
h5::chunk(128), h5::compress("gzip", 6)]] timeseries_t {
38+
unsigned long long timestamp_ns;
39+
[[h5::name("label")]] std::string tag;
40+
[[h5::ignore]] int internal_id;
41+
std::vector<double> readings;
42+
};
43+
}
44+
45+
2746
int main() {
2847
auto fd = h5::create("example.h5", H5F_ACC_TRUNC);
2948

30-
std::vector<float> data = {1.f, 2.f, 3.f, 4.f, 5.f};
31-
h5::write(fd, "sensor/readings", data);
49+
auto fd = h5::create("storage.h5");
50+
std::vector<timeseries_t> samples(100);
51+
h5::write(fd, "samples", samples);
3252

33-
auto result = h5::read<std::vector<float>>(fd, "sensor/readings");
34-
// result == {1.f, 2.f, 3.f, 4.f, 5.f}
53+
auto result = h5::read<std::vector<timeseries_t>>(fd, "samples");
3554
}
3655
```
3756
@@ -46,10 +65,10 @@ target_link_libraries(my_app PRIVATE h5cpp::h5cpp)
4665
| Requirement | Minimum | Tested ceiling |
4766
|---|---|---|
4867
| C++ standard | C++17 | C++23 |
49-
| HDF5 | 1.10.x | 1.12.2 |
68+
| HDF5 | 1.10.x | 1.14.6 |
5069
| CMake | 3.22 ||
5170

52-
C++20 upgrades the I/O pipeline to lock-free queues and enables `h5::view<T>` streaming ranges.
71+
C++20 enables `h5::view<T>` streaming ranges.
5372
C++23 adds `std::float16_t` dataset support.
5473

5574
## Installation
@@ -83,19 +102,27 @@ cmake --install build
83102
| Structs | POD / C / C++ structs via [h5cpp-compiler][compiler] |
84103
| Arrays | Up to rank 7 |
85104

86-
## v1.12 Highlights
87-
88-
- **`std::valarray<T>`** read/write support
89-
- **Iterator containers**`std::list`, `std::deque`, `std::set`, `std::unordered_set` and their multi- variants
90-
- **`std::complex<T>`** datasets
91-
- **`std::float16_t`** (C++23 IEEE 754 half-precision)
92-
- **Rank-7** array support
93-
- **Expanded attribute** type coverage
94-
- **FAPL-scoped worker pool**`h5::create(..., h5::threads{N} | h5::backpressure{M})` opts the file into parallel filter compression; all chunked datasets opened on that file (and pt_t built from them) inherit the pool. The pool only parallelizes gzip/zstd and never touches the HDF5 C-API, so it is throughput-neutral versus the classic single-threaded build.
95-
- **`-DH5CPP_MULTITHREAD` build mode** — a compile-time option that serializes every h5cpp→HDF5 C-API call behind one process-global recursive mutex, taken once at the outermost boundary via a thread-local recursion depth (mirroring HDF5's own `--enable-threadsafe` design: a lock, not a dedicated thread). This makes concurrent writers into one file safe even on a Threadsafety-OFF HDF5, and compiles to a zero-cost no-op in a classic build. Verified green on HDF5 1.12.3 and 2.1.1 (62/62 ctest, 40/40 concurrent-writer stress, TSan-clean under Clang 20).
96-
- **HDF5 1.12.2 ceiling** — tested and verified; `H5Dvlen_reclaim` / reference API compatibility
97-
- **Windows MSVC** in the CI matrix
98-
- **ASan + UBSan + TSan** clean on Clang 20
105+
## v1.14.0
106+
107+
v1.14.0 closes the v1.12.x line — a cycle organized around eliminating the performance and concurrency objections that push teams from HDF5 toward ad-hoc formats.
108+
109+
- **STL non-contiguous and sequence containers**`std::valarray`, `std::list`, `std::deque`, `std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset` all route through the unified Walter Brown trait-based dispatch. `std::complex<T>` and `std::float16_t` (C++23 half-precision) datasets added.
110+
- **Rank-7 arrays** — up to seven-dimensional arrays supported, matching the HDF5 C library limit.
111+
- **Expanded attribute coverage** — all scalar, string, and compound attribute types reachable through the same `h5::awrite` / `h5::aread` surface.
112+
- **SSSE3 rank-1 write fast path** — chunked 1-D writes use a bump-pointer arena, prefetch, nontemporal stores, and SIMD shuffle/unshuffle for element sizes 2, 4, and 8 bytes. No API changes; existing code picks it up automatically on x86 targets. Non-x86 targets use the scalar path unchanged.
113+
- **In-place filter pipeline** — shuffle, Fletcher-32, scale-offset, and nbit run without heap allocation, cutting per-chunk overhead on write-heavy workloads.
114+
- **Transparent concurrent compression** — the filter pipeline (gzip/zstd) runs across a per-file worker pool internally; the write API stays synchronous and single-threaded. Activate at file open with `h5::create(..., h5::threads{N} | h5::backpressure{M})`; no THREAD_SAFE HDF5 build required.
115+
- **Parallel decompression** — rank-1 chunked reads decompress across the same per-file pool, scaling with available threads.
116+
- **`h5::view<T>` streaming ranges** — C++20 range view over chunked datasets; `for (auto chunk : h5::view<std::vector<float>>(ds))` iterates multi-GB datasets one chunk at a time without materialising the full dataset in memory. Any container satisfying Walter Brown's detection idiom (`data()`, `value_type`, `size()`) works as the element type, so Abseil, Folly, EASTL, and Boost.Container all participate without registration.
117+
- **Gorilla XOR filter** *(experimental)* — delta-of-delta XOR codec for `float32`/`float64` time-series (Facebook Gorilla algorithm). Interoperability with h5py and the HDF5 C library for Gorilla-compressed datasets is not yet tested.
118+
- **Scatter/gather dispatch**`H5CPP_REGISTER_SCATTER` lets any third-party container opt into `h5::read` / `h5::write` without modifying the library.
119+
- **Compiler-assisted reflection**`h5cpp-compiler`, a Clang LibTooling pre-build tool, emits HDF5 compound descriptors and scatter/gather helpers for any non-POD struct without intrusive macros. Struct members are annotated with C++26-style attributes; the tool walks the AST at build time and generates the descriptors. C++26 static reflection is on the roadmap as the macro-free successor.
120+
- **SWMR**`swmr_write_t` / `swmr_read_t` tags enable live readers to observe an active writer without closing the file. Requires HDF5 ≥ 1.12.3; `H5CPP_HAS_SWMR` is set automatically by CMake.
121+
- **HDF5 2.x compatibility**`H5Dread_chunk2` buffer-sizing fix; existing code runs correctly on HDF5 2.x without source changes.
122+
- **Doxygen API reference** — full reference live at [vargalabs.github.io/h5cpp][docs], with I/O API, topics, and cookbook navigation axes.
123+
- **28 CMake cookbook examples** — basics through MPI, S3, sparse matrices, half-float, and custom pipelines; enable with `-DH5CPP_BUILD_EXAMPLES=ON`.
124+
- **Public CDash dashboard** — CI results and sanitiser status at <https://my.cdash.org/index.php?project=h5cpp>; community submissions welcomed.
125+
- **Coverage > 95%**, TSan-clean on Clang 20, ASan and UBSan clean across the full matrix.
99126

100127
## Documentation
101128

0 commit comments

Comments
 (0)