├── .clang-format ├── .git-blame-ignore-revs ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── build_failure.md │ ├── config.yml │ └── feature_request.md ├── build.sh ├── create_submodule_update_pr.sh ├── dependabot.yml ├── mamba_env_cxx14.yaml ├── mamba_env_cxx17.yaml ├── mamba_env_cxx20.yaml ├── run_examples.sh └── workflows │ ├── check_doxygen_awesome_version.yml │ ├── ci.yml │ ├── clang_format.yml │ ├── coverage.yml │ ├── gh-pages.yml │ ├── integration_trigger.yml │ └── version_file.yml ├── .gitignore ├── .gitmodules ├── .zenodo.json ├── AUTHORS.txt ├── CHANGELOG.md ├── CMakeLists.txt ├── LICENSE ├── README.md ├── bin └── format.sh ├── cmake ├── HighFiveConfig.cmake ├── HighFiveFlags.cmake ├── HighFiveOptionalDependencies.cmake └── HighFiveWarnings.cmake ├── codecov.yml ├── doc ├── CMakeLists.txt ├── Doxyfile ├── DoxygenLayout.xml ├── developer_guide.md ├── doxygen-awesome-css │ ├── doxygen-awesome.css │ └── update_doxygen_awesome.sh ├── installation.md ├── migration_guide.md └── poster │ ├── example1_hdf5.cpp │ ├── example1_highfive.cpp │ ├── example3.cpp │ ├── example6.cpp │ ├── example_boost.cpp │ ├── example_boost_ublas.cpp │ ├── example_easy_h5py.py │ ├── example_easy_highfive.cpp │ ├── example_props.cpp │ ├── examples.js │ ├── godbolt.org.ico │ └── index.html ├── include └── highfive │ ├── H5Attribute.hpp │ ├── H5DataSet.hpp │ ├── H5DataSpace.hpp │ ├── H5DataType.hpp │ ├── H5Easy.hpp │ ├── H5Exception.hpp │ ├── H5File.hpp │ ├── H5Group.hpp │ ├── H5Object.hpp │ ├── H5PropertyList.hpp │ ├── H5Reference.hpp │ ├── H5Selection.hpp │ ├── H5Utility.hpp │ ├── H5Version.hpp │ ├── H5Version.hpp.in │ ├── bits │ ├── H5Annotate_traits.hpp │ ├── H5Annotate_traits_misc.hpp │ ├── H5Attribute_misc.hpp │ ├── H5Converter_misc.hpp │ ├── H5DataSet_misc.hpp │ ├── H5DataType_misc.hpp │ ├── H5Dataspace_misc.hpp │ ├── H5Exception_misc.hpp │ ├── H5File_misc.hpp │ ├── H5Friends.hpp │ ├── H5Inspector_decl.hpp │ ├── H5Inspector_misc.hpp │ ├── H5Iterables_misc.hpp │ ├── H5Node_traits.hpp │ ├── H5Node_traits_misc.hpp │ ├── H5Object_misc.hpp │ ├── H5Path_traits.hpp │ ├── H5Path_traits_misc.hpp │ ├── H5PropertyList_misc.hpp │ ├── H5ReadWrite_misc.hpp │ ├── H5Reference_misc.hpp │ ├── H5Selection_misc.hpp │ ├── H5Slice_traits.hpp │ ├── H5Slice_traits_misc.hpp │ ├── H5Utils.hpp │ ├── H5_definitions.hpp │ ├── assert_compatible_spaces.hpp │ ├── compute_total_size.hpp │ ├── convert_size_vector.hpp │ ├── h5_wrapper.hpp │ ├── h5a_wrapper.hpp │ ├── h5d_wrapper.hpp │ ├── h5e_wrapper.hpp │ ├── h5f_wrapper.hpp │ ├── h5g_wrapper.hpp │ ├── h5i_wrapper.hpp │ ├── h5l_wrapper.hpp │ ├── h5o_wrapper.hpp │ ├── h5p_wrapper.hpp │ ├── h5r_wrapper.hpp │ ├── h5s_wrapper.hpp │ ├── h5t_wrapper.hpp │ ├── inspector_stl_span_misc.hpp │ ├── squeeze.hpp │ ├── string_padding.hpp │ └── xtensor_header_version.hpp │ ├── boost.hpp │ ├── boost_multi_array.hpp │ ├── boost_span.hpp │ ├── boost_ublas.hpp │ ├── eigen.hpp │ ├── experimental │ └── opencv.hpp │ ├── h5easy_bits │ ├── H5Easy_Eigen.hpp │ ├── H5Easy_misc.hpp │ ├── H5Easy_public.hpp │ ├── H5Easy_scalar.hpp │ └── default_io_impl.hpp │ ├── half_float.hpp │ ├── highfive.hpp │ ├── span.hpp │ └── xtensor.hpp ├── src ├── benchmarks │ ├── Makefile │ ├── README.md │ ├── hdf5_bench.cpp │ ├── hdf5_bench_improved.cpp │ ├── highfive_bench.cpp │ ├── imgs │ │ ├── bench_hdf5_base.png │ │ ├── bench_hdf5_improved.png │ │ └── bench_highfive.png │ └── run_benchmark.sh └── examples │ ├── CMakeLists.txt │ ├── boost_multi_array_2D.cpp │ ├── boost_multiarray_complex.cpp │ ├── boost_ublas_double.cpp │ ├── broadcasting_arrays.cpp │ ├── compound_types.cpp │ ├── create_attribute_string_integer.cpp │ ├── create_dataset_double.cpp │ ├── create_dataset_half_float.cpp │ ├── create_datatype.cpp │ ├── create_extensible_dataset.cpp │ ├── create_large_attribute.cpp │ ├── create_page_allocated_files.cpp │ ├── easy_attribute.cpp │ ├── easy_dumpoptions.cpp │ ├── easy_load_dump.cpp │ ├── eigen_map.cpp │ ├── eigen_matrix.cpp │ ├── eigen_vector.cpp │ ├── hl_hdf5_inmemory_files.cpp │ ├── parallel_hdf5_collective_io.cpp │ ├── parallel_hdf5_independent_io.cpp │ ├── read_write_dataset_string.cpp │ ├── read_write_raw_ptr.cpp │ ├── read_write_single_scalar.cpp │ ├── read_write_std_span.cpp │ ├── read_write_std_strings.cpp │ ├── read_write_vector_dataset.cpp │ ├── read_write_vector_dataset_references.cpp │ ├── readme_snippet.cpp │ ├── renaming_objects.cpp │ ├── select_by_id_dataset_cpp11.cpp │ ├── select_partial_dataset_cpp11.cpp │ └── select_slices.cpp └── tests ├── cmake_integration ├── README.md ├── application │ ├── CMakeLists.txt │ ├── deps │ │ └── .gitignore │ └── hi5_application.cpp ├── dependent_library │ ├── CMakeLists.txt │ ├── cmake │ │ └── Hi5DependentConfig.cmake.in │ ├── include │ │ └── hi5_dependent │ │ │ ├── read.hpp │ │ │ └── write.hpp │ └── src │ │ └── hi5_dependent │ │ ├── boost.cpp │ │ ├── read_vector.cpp │ │ └── write_vector.cpp ├── test_cmake_integration.sh └── test_dependent_library │ ├── CMakeLists.txt │ └── test_dependent_library.cpp └── unit ├── CMakeLists.txt ├── compary_arrays.hpp ├── create_traits.hpp ├── data_generator.hpp ├── supported_types.hpp ├── test_all_types.cpp ├── test_boost.cpp ├── test_empty_arrays.cpp ├── test_high_five_selection.cpp ├── test_legacy.cpp ├── test_opencv.cpp ├── test_stl.cpp ├── test_string.cpp ├── test_xtensor.cpp ├── tests_high_five.hpp ├── tests_high_five_base.cpp ├── tests_high_five_data_type.cpp ├── tests_high_five_easy.cpp ├── tests_high_five_parallel.cpp └── tests_import_public_headers.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: -2 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveAssignments: false 5 | AlignConsecutiveDeclarations: false 6 | AlignConsecutiveMacros: true 7 | AlignEscapedNewlinesLeft: true 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: Empty 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakBeforeMultilineStrings: true 17 | AlwaysBreakTemplateDeclarations: true 18 | BasedOnStyle: WebKit 19 | BinPackArguments: false 20 | BinPackParameters: false 21 | BraceWrapping: 22 | AfterClass: false 23 | AfterControlStatement: false 24 | AfterEnum: false 25 | AfterExternBlock: false 26 | AfterFunction: false 27 | AfterNamespace: false 28 | AfterStruct: false 29 | AfterUnion: false 30 | BeforeCatch: false 31 | BeforeElse: false 32 | BreakBeforeBraces: Custom 33 | BreakBeforeBinaryOperators: false 34 | BreakBeforeTernaryOperators: true 35 | BreakConstructorInitializersBeforeComma: true 36 | BreakStringLiterals: true 37 | ColumnLimit: 100 38 | CommentPragmas: '^\\.+' 39 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 40 | ConstructorInitializerIndentWidth: 4 41 | ContinuationIndentWidth: 4 42 | Cpp11BracedListStyle: true 43 | DerivePointerAlignment: false 44 | DerivePointerBinding: true 45 | ExperimentalAutoDetectBinPacking: false 46 | FixNamespaceComments: true 47 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 48 | IncludeCategories: 49 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 50 | Priority: 2 51 | - Regex: '^(<|"(gtest|isl|json)/)' 52 | Priority: 3 53 | - Regex: '.*' 54 | Priority: 1 55 | IncludeIsMainRegex: '$' 56 | IndentCaseLabels: false 57 | IndentWidth: 4 58 | IndentWrappedFunctionNames: false 59 | KeepEmptyLinesAtTheStartOfBlocks: false 60 | Language: Cpp 61 | MaxEmptyLinesToKeep: 2 62 | NamespaceIndentation: None 63 | PenaltyBreakAssignment: 40 64 | PenaltyBreakBeforeFirstCallParameter: 100 65 | PenaltyBreakComment: 60 66 | PenaltyBreakFirstLessLess: 120 67 | PenaltyBreakString: 1000 68 | PenaltyExcessCharacter: 1000000 69 | PenaltyReturnTypeOnItsOwnLine: 200 70 | PointerAlignment: Left 71 | PointerBindsToType: true 72 | ReflowComments: true 73 | SortIncludes: false 74 | SpaceAfterCStyleCast: true 75 | SpaceAfterTemplateKeyword: true 76 | SpaceBeforeAssignmentOperators: true 77 | SpaceBeforeCpp11BracedList: false 78 | SpaceBeforeCtorInitializerColon: false 79 | SpaceBeforeInheritanceColon: false 80 | SpaceBeforeParens: ControlStatements 81 | SpaceBeforeRangeBasedForLoopColon: false 82 | SpaceInEmptyBlock: false 83 | SpaceInEmptyParentheses: false 84 | SpacesBeforeTrailingComments: 2 85 | SpacesInAngles: false # '< ' style 86 | SpacesInContainerLiterals: false 87 | SpacesInCStyleCastParentheses: false 88 | SpacesInParentheses: false # '(' style 89 | SpacesInSquareBrackets: false 90 | Standard: c++14 91 | TabWidth: 4 92 | UseTab: Never 93 | ... 94 | -------------------------------------------------------------------------------- /.git-blame-ignore-revs: -------------------------------------------------------------------------------- 1 | # clang-format the whole repository 2 | 6fc243144b6a7802bf29d3fbb2c028051a71ca28 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | Please give a clear and concise description of the bug. For us to be able to 12 | fix the bug we need to be able to reproduce it. As a result, if you provide a 13 | reproducer, i.e. code that exhibits the bug (incl. build instructions) but is 14 | stripped of all unessential complexity, the chance of getting the issue fixed 15 | is much higher. 16 | 17 | **Version Information** 18 | - HighFive: 19 | - Compiler: 20 | - [optional] OS: 21 | - [optional] CMake: 22 | - [optional] HDF5: 23 | 24 | **Style Guide** 25 | 1. Please paste text as text and not as a screen shot. 26 | 2. If in doubt paste too much output rather than too little, i.e. don't be too 27 | scared of a large wall of text. Especially, if it's a compiler error. 28 | (Anything past the first error is largely uninformative and can be safely 29 | stripped.) 30 | 3. Please strip all boilerplate. 31 | 32 | **Markdown summary** 33 | Some include `code` and a block: 34 | ``` 35 | void foo(); 36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/build_failure.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Build failure 3 | about: Report an issue with the build-system. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Bug Description** 11 | Unfortunately, build failures tend to be highly specific and there's many 12 | things that could go wrong on both our and your side. Therefore, a reproducer 13 | is essential. You could try the minimal setup found here: 14 | https://github.com/BlueBrain/HighFive/blob/master/doc/installation.md#manually-install-highfive 15 | 16 | from there you can work upwards by adding complexity until you reproduce the 17 | issue. 18 | 19 | Once you have a reproducer, please paste it and the exact `cmake` command used to 20 | configure the build and include the output. For the compilation phase please 21 | ensure that the actual compiler invocation is visible, e.g., 22 | ``` 23 | $ cmake --build build --verbose 24 | [ 50%] Building CXX object CMakeFiles/dummy.dir/dummy.cpp.o 25 | /usr/bin/c++ ... -isystem ${HIGHFIVE_ROOT}/include -isystem ${HDF5_ROOT}/include ... -c dummy.cpp 26 | ``` 27 | and include at least the first error message. (If in doubt include more rather 28 | than less output.) 29 | 30 | **Version Information** 31 | - HighFive: 32 | - Compiler: 33 | - OS: 34 | - CMake: 35 | - HDF5: 36 | 37 | **Style Guide** 38 | 1. Please paste text as text and not as a screen shot. 39 | 2. If in doubt paste too much output rather than too little, i.e. don't be too 40 | scared of a large wall of text. Especially, if it's a compiler error. 41 | (Anything past the first error is largely uninformative and can be safely 42 | stripped.) 43 | 3. Please strip all boilerplate. 44 | 45 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: HighFive Community Support 4 | url: https://github.com/BlueBrain/HighFive/discussions 5 | about: Please ask and answer questions here. 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | -------------------------------------------------------------------------------- /.github/build.sh: -------------------------------------------------------------------------------- 1 | # Build env 2 | 3 | [ "$CC" ] && $CC --version 4 | cmake --version 5 | set -x 6 | export HIGHFIVE_BUILD=$GITHUB_WORKSPACE/build 7 | cmake -B $HIGHFIVE_BUILD -S $GITHUB_WORKSPACE \ 8 | -DHIGHFIVE_HAS_WERROR=On \ 9 | -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ 10 | -DCMAKE_INSTALL_PREFIX=$INSTALL_DIR \ 11 | "${CMAKE_OPTIONS[@]}" 12 | cmake --build $HIGHFIVE_BUILD --config $BUILD_TYPE --parallel 2 --verbose 13 | -------------------------------------------------------------------------------- /.github/create_submodule_update_pr.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Usage: 4 | # $0 PACKAGE_NAME VERSION 5 | # 6 | # Before calling this script, run the commands to update the dependency. If 7 | # there dependency shouldn't update then the script must not modify the repo. 8 | # 9 | # When the repo is in the updated state, run this script. It will commit 10 | # everything and create a PR. 11 | # 12 | # The PR title is `Update ${PACKAGE_NAME} to ${VERSION}` the script checks for 13 | # this string and only creates a new PR if the string isn't the title of an 14 | # existing PR. 15 | # 16 | # PACKAGE_NAME is an identifier of the package, no spaces. Doesn't need to be 17 | # the exact name of the dependency. 18 | # 19 | # VERSION an identifier of the next version of the package, no spaces. This 20 | # variable must be the same if the version if the same and different if 21 | # the version is different. However, it doesn't have to be a `x.y.z` it 22 | # could be a Git SHA, or something else. 23 | 24 | set -eu 25 | 26 | PACKAGE_NAME=$1 27 | VERSION=$2 28 | BRANCH=update-${PACKAGE_NAME}-${VERSION} 29 | COMMIT_MESSAGE="Update ${PACKAGE_NAME} to ${VERSION}" 30 | 31 | if [[ -z "${PACKAGE_NAME}" ]] 32 | then 33 | echo "Empty PACKAGE_NAME." 34 | exit -1 35 | fi 36 | 37 | if [[ -z "${VERSION}" ]] 38 | then 39 | echo "Empty VERSION." 40 | exit -1 41 | fi 42 | 43 | 44 | # NOTE: In a later runs of CI we will search for PR with this exact 45 | # title. Only if no such PR exists will the script create a 46 | # new PR. 47 | PR_TITLE="Update ${PACKAGE_NAME} to ${VERSION}" 48 | 49 | if [[ -z "$(git status --porcelain)" ]] 50 | then 51 | echo "No differences detected: ${PACKAGE_NAME} is up-to-date." 52 | exit 0 53 | fi 54 | 55 | if [[ -z "$(gh pr list --state all --search "${PR_TITLE}")" ]] 56 | then 57 | 58 | git checkout -b $BRANCH 59 | git config user.name github-actions 60 | git config user.email github-actions@github.com 61 | git commit -a -m "${COMMIT_MESSAGE}" 62 | 63 | git push -u origin ${BRANCH} 64 | gh pr create \ 65 | --title "${PR_TITLE}" \ 66 | --body "This PR was generated by a Github Actions workflow." 67 | 68 | else 69 | echo "Old PR detected: didn't create a new one." 70 | fi 71 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Check GitHub Actions 2 | version: 2 3 | updates: 4 | 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | -------------------------------------------------------------------------------- /.github/mamba_env_cxx14.yaml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | dependencies: 4 | - boost-cpp 5 | - catch2 6 | - cmake 7 | - doxygen 8 | - eigen 9 | - graphviz 10 | - hdf5 11 | - xtensor<0.26 12 | - xtl 13 | -------------------------------------------------------------------------------- /.github/mamba_env_cxx17.yaml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | dependencies: 4 | - boost-cpp 5 | - catch2 6 | - cmake 7 | - doxygen 8 | - eigen 9 | - graphviz 10 | - hdf5 11 | - xtensor>=0.26 12 | - xtl 13 | -------------------------------------------------------------------------------- /.github/mamba_env_cxx20.yaml: -------------------------------------------------------------------------------- 1 | channels: 2 | - conda-forge 3 | dependencies: 4 | - boost-cpp 5 | - catch2 6 | - cmake 7 | - doxygen 8 | - eigen 9 | - graphviz 10 | - hdf5 11 | - xtensor<0.26 12 | - xtl 13 | -------------------------------------------------------------------------------- /.github/run_examples.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | set -eu 4 | 5 | if [[ $# -eq 0 ]] 6 | then 7 | examples_dir="." 8 | elif [[ $# -eq 1 ]] 9 | then 10 | examples_dir="$1" 11 | else 12 | echo "Usage: $0 [EXAMPLES_DIR]" 13 | exit -1 14 | fi 15 | 16 | for f in "${examples_dir}"/*_bin 17 | do 18 | echo "-- ${f}" 19 | if [[ "${f}" == *"parallel_"* ]] 20 | then 21 | mpiexec -np 2 "${f}" 22 | else 23 | "${f}" 24 | fi 25 | done 26 | -------------------------------------------------------------------------------- /.github/workflows/check_doxygen_awesome_version.yml: -------------------------------------------------------------------------------- 1 | name: Auto-update doxygen-awesome 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: 0 2 * * 1 7 | 8 | jobs: 9 | check-for-updates: 10 | runs-on: ubuntu-latest 11 | env: 12 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | - name: Open PR if doxygen-awesome outdated. 17 | run: | 18 | 19 | VERSION=$(doc/doxygen-awesome-css/update_doxygen_awesome.sh "$(mktemp -d)") 20 | .github/create_submodule_update_pr.sh doxygen-awesome ${VERSION} 21 | -------------------------------------------------------------------------------- /.github/workflows/clang_format.yml: -------------------------------------------------------------------------------- 1 | name: ClangFormat 2 | 3 | permissions: read-all 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}#${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | on: 10 | workflow_dispatch: 11 | pull_request: 12 | branches: 13 | - master 14 | - main 15 | - v2.x 16 | 17 | jobs: 18 | Code_Format: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: Run clang-format 25 | run: | 26 | bash bin/format.sh 27 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | permissions: read-all 4 | 5 | concurrency: 6 | group: ${{ github.workflow }}#${{ github.ref }} 7 | cancel-in-progress: true 8 | 9 | on: 10 | push: 11 | branches: 12 | - master 13 | - main 14 | - v2.x 15 | pull_request: 16 | branches: 17 | - master 18 | - main 19 | - v2.x 20 | paths-ignore: 21 | - '**.md' 22 | - '**.rst' 23 | - 'doc/**' 24 | 25 | env: 26 | BUILD_TYPE: RelWithDebInfo 27 | INSTALL_DIR: install 28 | 29 | jobs: 30 | # Job producing code coverage report 31 | # ================================== 32 | Code_coverage: 33 | runs-on: ubuntu-22.04 34 | 35 | steps: 36 | - name: "Install libraries" 37 | run: | 38 | sudo apt-get update 39 | sudo apt-get install ninja-build lcov 40 | sudo apt-get install libhdf5-dev libsz2 libboost-all-dev libeigen3-dev libopencv-dev 41 | sudo apt-get install libxtensor-dev 42 | 43 | - uses: actions/checkout@v4 44 | with: 45 | fetch-depth: 1 46 | submodules: true 47 | 48 | - name: Build for code coverage 49 | run: | 50 | CMAKE_OPTIONS=( 51 | -GNinja 52 | -DHIGHFIVE_TEST_BOOST:BOOL=ON 53 | -DHIGHFIVE_TEST_EIGEN:BOOL=ON 54 | -DHIGHFIVE_TEST_OPENCV:BOOL=ON 55 | -DHIGHFIVE_TEST_XTENSOR:BOOL=ON 56 | -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON 57 | -DHIGHFIVE_BUILD_DOCS:BOOL=FALSE 58 | -DCMAKE_CXX_FLAGS="-coverage -O0" 59 | ) 60 | source $GITHUB_WORKSPACE/.github/build.sh 61 | 62 | - name: Test for code coverage 63 | run: | 64 | lcov --capture --initial --directory . --no-external --output-file build/coverage-base.info 65 | (cd build; cmake --build . --target test) 66 | lcov --capture --directory . --no-external --output-file build/coverage-run.info 67 | (cd build; lcov --add-tracefile coverage-base.info --add-tracefile coverage-run.info --output-file coverage-combined.info) 68 | 69 | - uses: codecov/codecov-action@v5 70 | with: 71 | files: ./build/coverage-combined.info 72 | fail_ci_if_error: false 73 | verbose: true 74 | token: ${{ secrets.CODECOV_TOKEN }} 75 | -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | permissions: 4 | contents: read 5 | pages: write 6 | id-token: write 7 | 8 | on: 9 | push: 10 | branches: 11 | - main 12 | pull_request: 13 | branches: 14 | - v2.x 15 | - main 16 | 17 | # Allow only one concurrent deployment 18 | concurrency: 19 | group: ${{ github.workflow }}#${{ github.ref }} 20 | cancel-in-progress: true 21 | 22 | jobs: 23 | build: 24 | name: Build Documentation 25 | runs-on: ubuntu-latest 26 | defaults: 27 | run: 28 | shell: bash -l {0} 29 | 30 | steps: 31 | - name: Checkout repository 32 | uses: actions/checkout@v4 33 | with: 34 | submodules: 'recursive' 35 | fetch-depth: 0 36 | 37 | - name: Install dependencies 38 | run: | 39 | pkgs=( 40 | doxygen 41 | graphviz 42 | libhdf5-dev 43 | libboost-all-dev 44 | libeigen3-dev 45 | libxtensor-dev 46 | ) 47 | 48 | sudo apt-get update 49 | sudo apt-get install -y ${pkgs[@]} 50 | 51 | - name: Build documentation with CMake 52 | run: | 53 | CMAKE_OPTIONS=( 54 | -DHIGHFIVE_UNIT_TESTS=OFF 55 | ) 56 | cmake -B build -S . "${CMAKE_OPTIONS[@]}" 57 | cmake --build build --target doc 58 | cp -r doc/poster build/doc/html/ 59 | 60 | - name: Upload artifact 61 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 62 | uses: actions/upload-pages-artifact@v3 63 | with: 64 | path: build/doc/html 65 | 66 | deploy: 67 | name: Deploy to GitHub Pages 68 | if: github.ref == 'refs/heads/main' && github.event_name == 'push' 69 | environment: 70 | name: github-pages 71 | url: ${{ steps.deployment.outputs.page_url }} 72 | runs-on: ubuntu-latest 73 | needs: build 74 | 75 | steps: 76 | - name: Deploy to GitHub Pages 77 | id: deployment 78 | uses: actions/deploy-pages@v4 79 | -------------------------------------------------------------------------------- /.github/workflows/integration_trigger.yml: -------------------------------------------------------------------------------- 1 | name: Integration Test Trigger 2 | 3 | permissions: read-all 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | - v2.x 10 | 11 | jobs: 12 | merge-PR: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Trigger integration tests on highfive-devs/bbp-integration 16 | run: | 17 | curl -X POST "https://api.github.com/repos/highfive-devs/bbp-integration/dispatches" \ 18 | -H 'Accept: application/vnd.github.everest-preview+json' \ 19 | -H "Authorization: Bearer ${{ secrets.BBP_INTEGRATION_TRIGGER }}" \ 20 | -H "X-GitHub-Api-Version: 2022-11-28" \ 21 | --data '{"event_type": "merge", "client_payload": { "repository": "'"$GITHUB_REPOSITORY"'" }}' 22 | -------------------------------------------------------------------------------- /.github/workflows/version_file.yml: -------------------------------------------------------------------------------- 1 | name: HighFive Check Version File 2 | 3 | permissions: read-all 4 | 5 | on: 6 | workflow_dispatch: 7 | push: 8 | branches: 9 | - master 10 | - main 11 | - v2.x 12 | pull_request: 13 | branches: 14 | - master 15 | - main 16 | - v2.x 17 | 18 | jobs: 19 | CheckVersion: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | with: 25 | submodules: true 26 | 27 | - name: "Install libraries" 28 | run: | 29 | sudo apt-get -qq update 30 | sudo apt-get -qq install libhdf5-dev ninja-build 31 | 32 | - name: Build 33 | run: | 34 | # Will trigger `configure_file` for H5Version.hpp. 35 | cmake -B build . 36 | 37 | - name: Test 38 | run: | 39 | # Check that the file hasn't changed, i.e. was updated 40 | # after changing the version number. 41 | ! git status | grep include/highfive/H5Version.hpp 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | tests/test_project 3 | .idea 4 | 5 | .vs/ 6 | .clang-format-venv/ 7 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/catch2"] 2 | path = deps/catch2 3 | url = https://github.com/catchorg/Catch2.git 4 | -------------------------------------------------------------------------------- /.zenodo.json: -------------------------------------------------------------------------------- 1 | { 2 | "creators": [ 3 | { 4 | "affiliation": "", 5 | "name": "Devresse, Adrien" 6 | }, 7 | { 8 | "affiliation": "", 9 | "name": "Cornu, Nicolas" 10 | }, 11 | { 12 | "affiliation": "", 13 | "name": "Grosheintz-Laval, Luc" 14 | }, 15 | { 16 | "affiliation": "", 17 | "name": "Awile, Omar" 18 | }, 19 | { 20 | "affiliation": "", 21 | "name": "de Geus, Tom" 22 | }, 23 | { 24 | "affiliation": "", 25 | "name": "Pereira, Fernando" 26 | }, 27 | { 28 | "affiliation": "", 29 | "name": "Wolf, Matthias" 30 | }, 31 | { 32 | "affiliation": "", 33 | "name": "HighFive Contributors" 34 | } 35 | ], 36 | 37 | "title": "HighFive - Header-only C++ HDF5 interface" 38 | } 39 | -------------------------------------------------------------------------------- /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Adrien Devresse 2 | Alexandru Săvulescu 3 | Ali Can Demiralp 4 | Angelos Plastropoulos 5 | @antonysigma 6 | Chris Byrohl 7 | Chris De Grendele 8 | @contre 9 | Daniel Nachbaur 10 | Dmitri Bichko 11 | @eudoxos 12 | Fernando L. Pereira 13 | @guoxy 14 | Haoran Ni 15 | Henry Schreiner 16 | @hn-sl 17 | Hunter Belanger 18 | @JaWSnl 19 | Jia Li 20 | John W. Peterson 21 | Jonas Karlsson 22 | Jorge Blanco Alonso 23 | Kerim Khemraev 24 | Luc Grosheintz 25 | Marian Heil 26 | Mario Emmenlauer 27 | Mark Bicknell 28 | Mathieu Bernard 29 | Matthias Wolf 30 | Maximilian Nöthe 31 | @Mightrider 32 | Mike DePalatis 33 | Mike Gevaert 34 | Moritz Koenemann 35 | Nico Jahn 36 | Nicolas Cornu (maintainer) 37 | Omar Awile 38 | Pablo Toharia 39 | Philip Deegan 40 | Philipp Gloor 41 | Pramod Kumbhar 42 | @Quark-X10 43 | Richard Shaw 44 | Rick Nitsche 45 | Rob Latham 46 | Sergio Botelh 47 | Sergio Rivas-Gomez 48 | @spacescientist 49 | Taiguara Tupinambás 50 | @timocafe 51 | Tino Wagner 52 | Tobias Klauser 53 | Tom de Geus 54 | Tom Vander Aa 55 | Torsten Reuschel 56 | Tristan Carel 57 | Wolf Vollprecht 58 | Y. Yang 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | 25 | 26 | -------------------------------------------------------------------------------- /bin/format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | clang_format_version="19.1.3" 5 | 6 | script_dir="$(dirname "${BASH_SOURCE[0]}")" 7 | venv_dir="$script_dir/../.clang-format-venv" 8 | 9 | if [ ! -d "$venv_dir" ]; then 10 | python3 -m venv "$venv_dir" 11 | source "$venv_dir/bin/activate" 12 | pip install clang-format=="$clang_format_version" 13 | deactivate 14 | fi 15 | 16 | source "$venv_dir/bin/activate" 17 | 18 | # Check if the installed version matches the expected version 19 | installed_version="$(pip show clang-format | grep Version | cut -d ' ' -f 2)" 20 | 21 | if [ "$installed_version" != "$clang_format_version" ]; then 22 | echo "Error: clang-format version mismatch. Expected $clang_format_version, got $installed_version" 23 | echo "Please remove the virtual environment and run the script again:" 24 | echo " rm -r \"$venv_dir\" && \"$0\"" 25 | exit 1 26 | fi 27 | 28 | clang-format --version 29 | for i in $(git ls-files | grep ".[ch]pp$"); do 30 | clang-format -i "$i" > /dev/null 2>&1 31 | done 32 | 33 | modified_files=$(git diff --name-only) 34 | if [ -n "$modified_files" ]; then 35 | echo "Some files are not well formatted:" 36 | echo "$modified_files" 37 | echo "" 38 | echo "The diff is:" 39 | git --no-pager diff 40 | echo "" 41 | echo "To correct the formatting run:" 42 | echo " $0" 43 | exit 1 44 | fi 45 | -------------------------------------------------------------------------------- /cmake/HighFiveConfig.cmake: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | if(NOT DEFINED HIGHFIVE_FIND_HDF5) 4 | set(HIGHFIVE_FIND_HDF5 On) 5 | endif() 6 | 7 | if(HIGHFIVE_FIND_HDF5) 8 | find_dependency(HDF5) 9 | endif() 10 | 11 | if(NOT TARGET HighFive) 12 | include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargets.cmake") 13 | 14 | if(HDF5_IS_PARALLEL) 15 | find_dependency(MPI) 16 | target_link_libraries(HighFive::HighFive INTERFACE MPI::MPI_C MPI::MPI_CXX) 17 | endif() 18 | 19 | add_library(HighFive ALIAS HighFive::HighFive) 20 | add_library(HighFiveInclude ALIAS HighFive::Include) 21 | endif() 22 | 23 | if(HIGHFIVE_XTENSOR_HEADER_VERSION) 24 | target_compile_definitions(HighFive::HighFive PUBLIC 25 | HIGHFIVE_XTENSOR_HEADER_VERSION=${HIGHFIVE_XTENSOR_HEADER_VERSION} 26 | ) 27 | endif() 28 | 29 | -------------------------------------------------------------------------------- /cmake/HighFiveFlags.cmake: -------------------------------------------------------------------------------- 1 | if(TARGET HighFiveFlags) 2 | # Allow multiple `include(HighFiveWarnings)`, which would 3 | # attempt to redefine `HighFiveWarnings` and fail without 4 | # this check. 5 | return() 6 | endif() 7 | 8 | add_library(HighFiveFlags INTERFACE) 9 | 10 | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 11 | if(HIGHFIVE_MAX_ERRORS) 12 | target_compile_options(HighFiveFlags 13 | INTERFACE 14 | -fmax-errors=${HIGHFIVE_MAX_ERRORS} 15 | ) 16 | endif() 17 | endif() 18 | 19 | if(HIGHFIVE_GLIBCXX_ASSERTIONS) 20 | target_compile_definitions(HighFiveFlags INTERFACE -D_GLIBCXX_ASSERTIONS) 21 | endif() 22 | 23 | if(HIGHFIVE_HAS_FRIEND_DECLARATIONS) 24 | target_compile_definitions(HighFiveFlags INTERFACE -DHIGHFIVE_HAS_FRIEND_DECLARATIONS=1) 25 | endif() 26 | 27 | if(HIGHFIVE_SANITIZER) 28 | target_compile_options(HighFiveFlags INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) 29 | target_link_options(HighFiveFlags INTERFACE -fsanitize=${HIGHFIVE_SANITIZER}) 30 | endif() 31 | -------------------------------------------------------------------------------- /cmake/HighFiveOptionalDependencies.cmake: -------------------------------------------------------------------------------- 1 | if(NOT TARGET HighFiveBoostDependency) 2 | add_library(HighFiveBoostDependency INTERFACE) 3 | if(HIGHFIVE_TEST_BOOST) 4 | find_package(Boost REQUIRED) 5 | target_link_libraries(HighFiveBoostDependency INTERFACE Boost::headers) 6 | # TODO check if we need Boost::disable_autolinking to cause: 7 | # -DBOOST_ALL_NO_LIB (does something on MSVC). 8 | target_compile_definitions(HighFiveBoostDependency INTERFACE HIGHFIVE_TEST_BOOST=1) 9 | endif() 10 | if(HIGHFIVE_TEST_BOOST_SPAN) 11 | target_compile_definitions(HighFiveBoostDependency INTERFACE HIGHFIVE_TEST_BOOST_SPAN=1) 12 | endif() 13 | endif() 14 | 15 | if(NOT TARGET HighFiveEigenDependency) 16 | add_library(HighFiveEigenDependency INTERFACE) 17 | if(HIGHFIVE_TEST_EIGEN) 18 | find_package(Eigen3 REQUIRED NO_MODULE) 19 | target_link_libraries(HighFiveEigenDependency INTERFACE Eigen3::Eigen) 20 | target_compile_definitions(HighFiveEigenDependency INTERFACE HIGHFIVE_TEST_EIGEN=1) 21 | endif() 22 | endif() 23 | 24 | if(NOT TARGET HighFiveXTensorDependency) 25 | add_library(HighFiveXTensorDependency INTERFACE) 26 | if(HIGHFIVE_TEST_XTENSOR) 27 | find_package(xtensor REQUIRED) 28 | target_link_libraries(HighFiveXTensorDependency INTERFACE xtensor) 29 | target_compile_definitions(HighFiveXTensorDependency INTERFACE HIGHFIVE_TEST_XTENSOR=1) 30 | 31 | if(HIGHFIVE_XTENSOR_HEADER_VERSION) 32 | target_compile_definitions(HighFiveXTensorDependency INTERFACE 33 | HIGHFIVE_XTENSOR_HEADER_VERSION=${HIGHFIVE_XTENSOR_HEADER_VERSION}) 34 | endif() 35 | endif() 36 | endif() 37 | 38 | if(NOT TARGET HighFiveOpenCVDependency) 39 | add_library(HighFiveOpenCVDependency INTERFACE) 40 | if(HIGHFIVE_TEST_OPENCV) 41 | find_package(OpenCV REQUIRED) 42 | target_include_directories(HighFiveOpenCVDependency SYSTEM INTERFACE ${OpenCV_INCLUDE_DIRS}) 43 | target_link_libraries(HighFiveOpenCVDependency INTERFACE ${OpenCV_LIBS}) 44 | target_compile_definitions(HighFiveOpenCVDependency INTERFACE HIGHFIVE_TEST_OPENCV=1) 45 | endif() 46 | endif() 47 | 48 | if(NOT TARGET HighFiveSpanDependency) 49 | add_library(HighFiveSpanDependency INTERFACE) 50 | if(HIGHFIVE_TEST_SPAN) 51 | target_compile_definitions(HighFiveSpanDependency INTERFACE HIGHFIVE_TEST_SPAN=1) 52 | endif() 53 | endif() 54 | 55 | if(NOT TARGET HighFiveOptionalDependencies) 56 | add_library(HighFiveOptionalDependencies INTERFACE) 57 | target_link_libraries(HighFiveOptionalDependencies INTERFACE 58 | HighFiveBoostDependency 59 | HighFiveEigenDependency 60 | HighFiveXTensorDependency 61 | HighFiveOpenCVDependency 62 | HighFiveSpanDependency 63 | ) 64 | endif() 65 | -------------------------------------------------------------------------------- /cmake/HighFiveWarnings.cmake: -------------------------------------------------------------------------------- 1 | if(TARGET HighFiveWarnings) 2 | # Allow multiple `include(HighFiveWarnings)`, which would 3 | # attempt to redefine `HighFiveWarnings` and fail without 4 | # this check. 5 | return() 6 | endif() 7 | 8 | add_library(HighFiveWarnings INTERFACE) 9 | 10 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" 11 | OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" 12 | OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") 13 | 14 | target_compile_options(HighFiveWarnings 15 | INTERFACE 16 | -Wall 17 | -Wextra 18 | -Wshadow 19 | -Wnon-virtual-dtor 20 | -Wunused 21 | -Woverloaded-virtual 22 | -Wformat=2 23 | -Wconversion 24 | -Wsign-conversion 25 | ) 26 | endif() 27 | 28 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") 29 | target_compile_options(HighFiveWarnings 30 | INTERFACE 31 | -Wpedantic 32 | -Wcast-align 33 | -Wdouble-promotion 34 | ) 35 | 36 | target_compile_options(HighFiveWarnings 37 | INTERFACE 38 | -ftemplate-backtrace-limit=0 39 | ) 40 | 41 | if(HIGHFIVE_HAS_WERROR) 42 | target_compile_options(HighFiveWarnings 43 | INTERFACE 44 | -Werror 45 | -Wno-error=deprecated-declarations 46 | ) 47 | endif() 48 | endif() 49 | 50 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | informational: true 6 | patch: 7 | default: 8 | informational: true 9 | -------------------------------------------------------------------------------- /doc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Doxygen) 2 | if(Doxygen_FOUND) 3 | configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY) 4 | add_custom_target(doc COMMAND Doxygen::doxygen ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile) 5 | else() 6 | message(STATUS " Documentation (doc) cannot be built since Doxygen is not available.") 7 | endif() 8 | -------------------------------------------------------------------------------- /doc/doxygen-awesome-css/update_doxygen_awesome.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # 4 | # Copyright (c), 2022, Blue Brain Project 5 | # 6 | # Distributed under the Boost Software License, Version 1.0. 7 | # (See accompanying file LICENSE_1_0.txt or copy at 8 | # http://www.boost.org/LICENSE_1_0.txt) 9 | # 10 | 11 | set -e 12 | 13 | if [[ $# -ne 1 ]] 14 | then 15 | echo "Usage: $0 TMP_DIR" 16 | echo "" 17 | echo "TMP_DIR must point to a writeable, empty, temporary directory." 18 | 19 | exit 1 20 | fi 21 | 22 | TMP_DIR="$(realpath "$1")" 23 | DOXYGEN_AWESOME_DIR="$(dirname "$(realpath "$0")")" 24 | REPO_URL="https://github.com/jothepro/doxygen-awesome-css" 25 | REPO_DIR="${TMP_DIR}/doxygen-awesome-css" 26 | 27 | CONTENT_URL="https://raw.githubusercontent.com/jothepro/doxygen-awesome-css" 28 | 29 | mkdir -p "${TMP_DIR}" 30 | git clone ${REPO_URL} "${REPO_DIR}" 1>&2 31 | pushd "${REPO_DIR}" 1>&2 32 | 33 | VERSION="$(git tag -l | sed -e '/^v[0-9]*\.[0-9]*\.[0-9]*$/!d' | sort -V | tail -n 1)" 34 | 35 | popd 1>&2 36 | 37 | if [[ -z "$VERSION" ]] 38 | then 39 | exit 1 40 | fi 41 | 42 | STYLESHEET="doxygen-awesome.css" 43 | curl "${CONTENT_URL}/${VERSION}/${STYLESHEET}" \ 44 | --output "${DOXYGEN_AWESOME_DIR}/${STYLESHEET}" \ 45 | 1>&2 46 | 47 | echo "${VERSION}" 48 | -------------------------------------------------------------------------------- /doc/poster/example1_hdf5.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "hdf5.h" 3 | 4 | void data_io() { 5 | hid_t file_id, dset_id, dspace_id, group_id; /* identifiers */ 6 | herr_t status; 7 | 8 | // Setup dataset dimensions and input data 9 | int ndims = 1; 10 | hsize_t dims[ndims]; 11 | dims[0] = 50; 12 | std::vector data(50, 1); 13 | 14 | // Open a file 15 | file_id = H5Fcreate("new_file.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); 16 | 17 | // Create a group 18 | group_id = H5Gcreate2(file_id, "/group", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 19 | 20 | // Create a dataset 21 | dspace_id = H5Screate_simple(1, dims, NULL); 22 | dset_id = H5Dcreate2( 23 | group_id, "dset1", H5T_STD_I32BE, dspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 24 | 25 | // Write the data 26 | status = H5Dwrite(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data.data()); 27 | 28 | // Close dataset after writing 29 | status = H5Dclose(dset_id); 30 | 31 | // Retrieve result size and preallocate vector 32 | std::vector result; 33 | dset_id = H5Dopen(file_id, "/group/dset1", H5P_DEFAULT); 34 | dspace_id = H5Dget_space(dset_id); 35 | ndims = H5Sget_simple_extent_ndims(dspace_id); 36 | hsize_t res_dims[ndims]; 37 | status = H5Sget_simple_extent_dims(dspace_id, res_dims, NULL); 38 | int res_sz = 1; 39 | for (int i = 0; i < ndims; i++) { 40 | res_sz *= res_dims[i]; 41 | } 42 | result.resize(res_sz); 43 | 44 | // Read the data 45 | status = H5Dread(dset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, result.data()); 46 | 47 | // Close the dataset and group 48 | status = H5Dclose(dset_id); 49 | status = H5Gclose(group_id); 50 | 51 | // Close the file 52 | status = H5Fclose(file_id); 53 | } 54 | -------------------------------------------------------------------------------- /doc/poster/example1_highfive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using HighFive::File; 4 | 5 | void write_io() { 6 | std::vector d1(50, 1); 7 | 8 | // Open a file 9 | File file("tmp.h5", File::ReadWrite | File::Truncate); 10 | 11 | // Create DataSet and write data (short form) 12 | file.createDataSet("/group/dset1", d1); 13 | 14 | // Read the data 15 | std::vector d1_read; 16 | file.getDataSet("/group/dset1").read(d1_read); 17 | } 18 | -------------------------------------------------------------------------------- /doc/poster/example3.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | typedef struct { 5 | double width; 6 | double height; 7 | } Size2D; 8 | 9 | 10 | HighFive::CompoundType create_compound_Size2D() { 11 | return {{"width", HighFive::AtomicType{}}, {"height", HighFive::AtomicType{}}}; 12 | } 13 | 14 | HIGHFIVE_REGISTER_TYPE(Size2D, create_compound_Size2D) 15 | 16 | int data_io() { 17 | const std::string DATASET_NAME("points"); 18 | 19 | HighFive::File file("compounds.h5", HighFive::File::Truncate); 20 | 21 | auto t1 = create_compound_Size2D(); 22 | t1.commit(file, "Size2D"); 23 | 24 | std::vector pts = {{1., 2.5}, {3., 4.5}}; 25 | auto dataset = file.createDataSet(DATASET_NAME, pts); 26 | 27 | auto g1 = file.createGroup("group1"); 28 | g1.createAttribute(DATASET_NAME, pts); 29 | } 30 | -------------------------------------------------------------------------------- /doc/poster/example6.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | 8 | int main(int argc, char** argv) { 9 | int mpi_rank, mpi_size; 10 | const std::string DATASET_NAME("dset"); 11 | 12 | // initialize MPI 13 | MPI_Init(&argc, &argv); 14 | MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); 15 | MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); 16 | 17 | using namespace HighFive; 18 | try { 19 | // open a new file with the MPI IO driver for parallel Read/Write 20 | File file("parallel_highfive.h5", 21 | File::ReadWrite | File::Create | File::Truncate, 22 | MPIOFileDriver(MPI_COMM_WORLD, MPI_INFO_NULL)); 23 | 24 | // we define the size of our dataset to 25 | // lines : total number of mpi_rank 26 | // columns : 2 27 | std::vector dims(2); 28 | dims[0] = std::size_t(mpi_size); 29 | dims[1] = 2; 30 | 31 | // Create the dataset 32 | DataSet dset = file.createDataSet(DATASET_NAME, DataSpace(dims)); 33 | 34 | // Each node want to write its own rank two time in 35 | // its associated row 36 | int data[1][2] = {{mpi_rank, mpi_rank}}; 37 | 38 | // write it to the associated mpi_rank 39 | dset.select({std::size_t(mpi_rank), 0}, {1, 2}).write(data); 40 | 41 | } catch (const Exception& err) { 42 | // catch and print any HDF5 error 43 | std::cerr << err.what() << std::endl; 44 | MPI_Abort(MPI_COMM_WORLD, 1); 45 | } 46 | 47 | MPI_Finalize(); 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /doc/poster/example_boost.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define H5_USE_BOOST 1 4 | #include 5 | 6 | #include 7 | 8 | using complex_t = std::complex; 9 | 10 | void data_io() { 11 | boost::multi_array multi_array(boost::extents[3][2][1][1]); 12 | std::fill_n(multi_array.origin(), multi_array.num_elements(), 1.0); 13 | multi_array[1][1][0][0] = complex_t{1.1, 1.2}; 14 | 15 | HighFive::File file("multi_array_complex.h5", HighFive::File::Truncate); 16 | 17 | HighFive::DataSet dataset = 18 | file.createDataSet("multi_array", HighFive::DataSpace::From(multi_array)); 19 | 20 | dataset.write(multi_array); 21 | } 22 | -------------------------------------------------------------------------------- /doc/poster/example_boost_ublas.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define H5_USE_BOOST 1 4 | #include 5 | 6 | // In some versions of Boost (starting with 1.64), you have to 7 | // include the serialization header before ublas 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | using namespace HighFive; 14 | 15 | void data_io() { 16 | const std::string DATASET_NAME("dset"); 17 | const size_t size_x = 10; 18 | const size_t size_y = 10; 19 | 20 | try { 21 | typedef typename boost::numeric::ublas::matrix Matrix; 22 | 23 | // create a 10x10 matrix 24 | Matrix mat(size_x, size_y); 25 | 26 | // fill it 27 | for (std::size_t i = 0; i < size_x; ++i) { 28 | mat(i, i) = static_cast(i); 29 | } 30 | 31 | // Create a new HDF5 file 32 | File file("boost_ublas.h5", File::ReadWrite | File::Create | File::Truncate); 33 | 34 | DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(mat)); 35 | 36 | dataset.write(mat); 37 | 38 | Matrix result; 39 | dataset.read(result); 40 | 41 | std::cout << "Matrix result:\n" << result << std::endl; 42 | 43 | } catch (const Exception& err) { 44 | // catch and print any HDF5 error 45 | std::cerr << err.what() << std::endl; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /doc/poster/example_easy_h5py.py: -------------------------------------------------------------------------------- 1 | import h5py 2 | import numpy as np 3 | 4 | A = np.ones([10, 3]) 5 | 6 | with h5py.File("tmp.h5", "w") as file: 7 | 8 | # write dataset (automatically creates groups if needed) 9 | file["/path/to/A"] = A 10 | 11 | # read from dataset 12 | B = file["/path/to/A"] 13 | 14 | # write attribute 15 | file["/path/to/A"].attrs["date"] = "today" 16 | 17 | # read from attribute 18 | d = file["/path/to/A"].attrs["date"] 19 | 20 | # create extendible dataset and extend it 21 | dset = file.create_dataset("/path/to/extendible", (1,), maxshape=(None,)) 22 | dset[0] = 0 23 | 24 | for i in range(1, 10): 25 | dset.resize((i + 1,)) 26 | dset[i] = i 27 | -------------------------------------------------------------------------------- /doc/poster/example_easy_highfive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | int main() { 6 | xt::xarray A = xt::ones({10, 3}); 7 | 8 | // open a file 9 | H5Easy::File file("tmp.h5", H5Easy::File::Overwrite); 10 | 11 | // write dataset (automatically creates groups if needed) 12 | H5Easy::dump(file, "/path/to/A", A); 13 | 14 | // read from dataset 15 | auto B = H5Easy::load>(file, "/path/to/A"); 16 | 17 | // write attribute 18 | H5Easy::dumpAttribute(file, "/path/to/A", "date", std::string("today")); 19 | 20 | // read from attribute 21 | auto d = H5Easy::loadAttribute(file, "/path/to/A", "date"); 22 | 23 | // create extendible dataset and extend it 24 | for (size_t i = 0; i < 10; ++i) { 25 | H5Easy::dump(file, "/path/to/extendible", i, {i}); 26 | } 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /doc/poster/example_props.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace HighFive; 4 | 5 | int write_data() { 6 | FileDriver fdrv; 7 | 8 | fdrv.add(FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); 9 | fdrv.add(MetadataBlockSize(10240)); 10 | 11 | File file("example2.h5", File::Truncate, fdrv); 12 | 13 | GroupCreateProps props; 14 | props.add(EstimatedLinkInfo(1000, 500)); 15 | auto group = file.createGroup("g", props); 16 | 17 | DataSetCreateProps dsprops; 18 | dsprops.add(Chunking(std::vector{2, 2})); 19 | dsprops.add(Deflate(9)); 20 | 21 | 22 | std::vector d1(100000, 1); 23 | group.createDataSet("dset1", d1, dsprops); 24 | } 25 | -------------------------------------------------------------------------------- /doc/poster/examples.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function compile_on_godbolt(example_id) { 4 | 5 | let src = $('#' + example_id).attr("rawsrc"); 6 | 7 | let url = `https://godbolt.org/#g:!((g:!((g:!((h:codeEditor,i:(filename:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,source:'${src}'),l:'5',n:'0',o:'C%2B%2B+source+%231',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0'),(g:!((h:compiler,i:(compiler:g112,filters:(b:'0',binary:'1',commentOnly:'0',demangle:'0',directives:'0',execute:'1',intel:'0',libraryCode:'0',trim:'1'),flagsViewOpen:'1',fontScale:14,fontUsePx:'0',j:1,lang:c%2B%2B,libs:!((name:hdf5,ver:'1121'),(name:highfive,ver:trunk)),options:'',selection:(endColumn:1,endLineNumber:1,positionColumn:1,positionLineNumber:1,selectionStartColumn:1,selectionStartLineNumber:1,startColumn:1,startLineNumber:1),source:1,tree:'1'),l:'5',n:'0',o:'x86-64+gcc+11.2+(C%2B%2B,+Editor+%231,+Compiler+%231)',t:'0')),k:50,l:'4',n:'0',o:'',s:0,t:'0')),l:'2',n:'0',o:'',t:'0')),version:4`; 8 | window.open(url); 9 | 10 | } 11 | 12 | function setup_examples() { 13 | $(".example").each(function () { 14 | let cblock = this; 15 | let file = this.id + '.' + this.dataset.lang; 16 | $.ajax( {url: file, 17 | dataType: 'text', 18 | success: function( code ) { 19 | res = hljs.highlight(code, {language: cblock.dataset.lang, ignoreIllegals: true }); 20 | cblock.innerHTML += res.value; 21 | let encoded = encodeURIComponent(code); 22 | cblock.setAttribute("rawsrc",encoded); 23 | }}); 24 | 25 | }); 26 | 27 | $(".godbolt").each(function(idx, el) { 28 | let example_id = el.id.substring(3); 29 | el.addEventListener("click", function () { 30 | compile_on_godbolt(example_id); 31 | }); 32 | }); 33 | 34 | } 35 | 36 | 37 | setup_examples(); 38 | -------------------------------------------------------------------------------- /doc/poster/godbolt.org.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfive-devs/highfive/251828e3a17be255d64c362aa9758384d1e8d44a/doc/poster/godbolt.org.ico -------------------------------------------------------------------------------- /include/highfive/H5DataSet.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "H5DataSpace.hpp" 14 | #include "H5DataType.hpp" 15 | #include "H5Object.hpp" 16 | #include "bits/H5_definitions.hpp" 17 | #include "bits/H5Annotate_traits.hpp" 18 | #include "bits/H5Slice_traits.hpp" 19 | #include "bits/H5Path_traits.hpp" 20 | #include "bits/H5_definitions.hpp" 21 | 22 | namespace HighFive { 23 | 24 | /// 25 | /// \brief Class representing a dataset. 26 | /// 27 | class DataSet: public Object, 28 | public SliceTraits, 29 | public AnnotateTraits, 30 | public PathTraits { 31 | public: 32 | const static ObjectType type = ObjectType::Dataset; 33 | 34 | /// 35 | /// \brief getStorageSize 36 | /// \return returns the amount of storage allocated for a dataset. 37 | /// 38 | uint64_t getStorageSize() const; 39 | 40 | /// 41 | /// \brief getOffset 42 | /// \return returns DataSet address in file 43 | /// 44 | uint64_t getOffset() const; 45 | 46 | /// 47 | /// \brief getDataType 48 | /// \return return the datatype associated with this dataset 49 | /// 50 | DataType getDataType() const; 51 | 52 | /// 53 | /// \brief getSpace 54 | /// \return return the dataspace associated with this dataset 55 | /// 56 | DataSpace getSpace() const; 57 | 58 | /// 59 | /// \brief getMemSpace 60 | /// \return same than getSpace for DataSet, compatibility with Selection 61 | /// class 62 | /// 63 | DataSpace getMemSpace() const; 64 | 65 | 66 | /// \brief Change the size of the dataset 67 | /// 68 | /// This requires that the dataset was created with chunking, and you would 69 | /// generally want to have set a larger maxdims setting 70 | /// \param dims New size of the dataset 71 | void resize(const std::vector& dims); 72 | 73 | 74 | /// \brief Get the dimensions of the whole DataSet. 75 | /// This is a shorthand for getSpace().getDimensions() 76 | /// \return The shape of the current HighFive::DataSet 77 | /// 78 | inline std::vector getDimensions() const { 79 | return getSpace().getDimensions(); 80 | } 81 | 82 | /// \brief Get the total number of elements in the current dataset. 83 | /// E.g. 2x2x2 matrix has size 8. 84 | /// This is a shorthand for getSpace().getTotalCount() 85 | /// \return The shape of the current HighFive::DataSet 86 | /// 87 | inline size_t getElementCount() const { 88 | return getSpace().getElementCount(); 89 | } 90 | 91 | /// \brief Get the list of properties for creation of this dataset 92 | DataSetCreateProps getCreatePropertyList() const { 93 | return details::get_plist(*this, H5Dget_create_plist); 94 | } 95 | 96 | /// \brief Get the list of properties for accession of this dataset 97 | DataSetAccessProps getAccessPropertyList() const { 98 | return details::get_plist(*this, H5Dget_access_plist); 99 | } 100 | 101 | DataSet() = default; 102 | 103 | protected: 104 | using Object::Object; // bring DataSet(hid_t) 105 | 106 | DataSet(Object&& o) noexcept 107 | : Object(std::move(o)) {} 108 | 109 | friend class Reference; 110 | template 111 | friend class NodeTraits; 112 | }; 113 | 114 | } // namespace HighFive 115 | -------------------------------------------------------------------------------- /include/highfive/H5Group.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "H5Object.hpp" 14 | #include "bits/H5Friends.hpp" 15 | #include "bits/H5_definitions.hpp" 16 | #include "bits/H5Annotate_traits.hpp" 17 | #include "bits/H5Node_traits.hpp" 18 | #include "bits/H5Path_traits.hpp" 19 | 20 | namespace HighFive { 21 | 22 | namespace detail { 23 | /// \brief Internal hack to create an `Group` from an ID. 24 | /// 25 | /// WARNING: Creating an Group from an ID has implications w.r.t. the lifetime of the object 26 | /// that got passed via its ID. Using this method careless opens up the suite of issues 27 | /// related to C-style resource management, including the analog of double free, dangling 28 | /// pointers, etc. 29 | /// 30 | /// NOTE: This is not part of the API and only serves to work around a compiler issue in GCC which 31 | /// prevents us from using `friend`s instead. This function should only be used for internal 32 | /// purposes. The problematic construct is: 33 | /// 34 | /// template 35 | /// friend class SomeCRTP; 36 | /// 37 | /// \private 38 | Group make_group(hid_t); 39 | } // namespace detail 40 | 41 | /// 42 | /// \brief Represents an hdf5 group 43 | class Group: public Object, 44 | public NodeTraits, 45 | public AnnotateTraits, 46 | public PathTraits { 47 | public: 48 | const static ObjectType type = ObjectType::Group; 49 | 50 | Group() = default; 51 | 52 | std::pair getEstimatedLinkInfo() const; 53 | 54 | /// \brief Get the list of properties for creation of this group 55 | GroupCreateProps getCreatePropertyList() const { 56 | return details::get_plist(*this, H5Gget_create_plist); 57 | } 58 | 59 | Group(Object&& o) noexcept 60 | : Object(std::move(o)) {}; 61 | 62 | protected: 63 | using Object::Object; 64 | 65 | friend Group detail::make_group(hid_t); 66 | friend class File; 67 | friend class Reference; 68 | #if HIGHFIVE_HAS_FRIEND_DECLARATIONS 69 | template 70 | friend class ::HighFive::NodeTraits; 71 | #endif 72 | }; 73 | 74 | inline std::pair Group::getEstimatedLinkInfo() const { 75 | auto gcpl = getCreatePropertyList(); 76 | auto eli = EstimatedLinkInfo(gcpl); 77 | return std::make_pair(eli.getEntries(), eli.getNameLength()); 78 | } 79 | 80 | namespace detail { 81 | inline Group make_group(hid_t hid) { 82 | return Group(hid); 83 | } 84 | } // namespace detail 85 | 86 | } // namespace HighFive 87 | -------------------------------------------------------------------------------- /include/highfive/H5Object.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "bits/H5_definitions.hpp" 17 | #include "bits/H5Friends.hpp" 18 | 19 | namespace HighFive { 20 | 21 | /// 22 | /// \brief Enum of the types of objects (H5O api) 23 | /// 24 | enum class ObjectType { 25 | File, 26 | Group, 27 | UserDataType, 28 | DataSpace, 29 | Dataset, 30 | Attribute, 31 | Other // Internal/custom object type 32 | }; 33 | 34 | 35 | class Object { 36 | public: 37 | // move constructor, reuse hid 38 | Object(Object&& other) noexcept; 39 | 40 | /// 41 | /// \brief isValid 42 | /// \return true if current Object is a valid HDF5Object 43 | /// 44 | bool isValid() const noexcept; 45 | 46 | /// 47 | /// \brief getId 48 | /// \return internal HDF5 id to the object 49 | /// provided for C API compatibility 50 | /// 51 | hid_t getId() const noexcept; 52 | 53 | /// 54 | /// \brief Retrieve several infos about the current object (address, dates, etc) 55 | /// 56 | ObjectInfo getInfo() const; 57 | 58 | /// 59 | /// \brief Gets the fundamental type of the object (dataset, group, etc) 60 | /// \exception ObjectException when the _hid is negative or the type 61 | /// is custom and not registered yet 62 | /// 63 | ObjectType getType() const; 64 | 65 | // Check if refer to same object 66 | bool operator==(const Object& other) const noexcept { 67 | return _hid == other._hid; 68 | } 69 | 70 | protected: 71 | // empty constructor 72 | Object(); 73 | 74 | // copy constructor, increase reference counter 75 | Object(const Object& other); 76 | 77 | // Init with an low-level object id 78 | explicit Object(hid_t); 79 | 80 | // decrease reference counter 81 | ~Object(); 82 | 83 | // Copy-Assignment operator 84 | Object& operator=(const Object& other); 85 | 86 | hid_t _hid; 87 | 88 | private: 89 | friend class Reference; 90 | friend class CompoundType; 91 | 92 | #if HIGHFIVE_HAS_FRIEND_DECLARATIONS 93 | template 94 | friend class NodeTraits; 95 | template 96 | friend class AnnotateTraits; 97 | template 98 | friend class PathTraits; 99 | #endif 100 | }; 101 | 102 | 103 | /// 104 | /// \brief A class for accessing hdf5 objects info 105 | /// 106 | class ObjectInfo { 107 | public: 108 | /// \brief Retrieve the address of the object (within its file) 109 | /// \deprecated Deprecated since HighFive 2.2. Soon supporting VOL tokens 110 | H5_DEPRECATED("Deprecated since HighFive 2.2. Soon supporting VOL tokens") 111 | haddr_t getAddress() const noexcept; 112 | 113 | /// \brief Retrieve the number of references to this object 114 | size_t getRefCount() const noexcept; 115 | 116 | /// \brief Retrieve the object's creation time 117 | time_t getCreationTime() const noexcept; 118 | 119 | /// \brief Retrieve the object's last modification time 120 | time_t getModificationTime() const noexcept; 121 | 122 | protected: 123 | #if (H5Oget_info_vers < 3) 124 | H5O_info_t raw_info; 125 | #else 126 | // Use compat H5O_info1_t while getAddress() is supported (deprecated) 127 | H5O_info1_t raw_info; 128 | #endif 129 | 130 | friend class Object; 131 | }; 132 | 133 | } // namespace HighFive 134 | 135 | #include "bits/H5Object_misc.hpp" 136 | -------------------------------------------------------------------------------- /include/highfive/H5Reference.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020, EPFL - Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | #include "bits/H5_definitions.hpp" 19 | 20 | namespace HighFive { 21 | 22 | namespace details { 23 | template 24 | struct inspector; 25 | } 26 | /// 27 | /// \brief An HDF5 (object) reference type 28 | /// 29 | /// HDF5 object references allow pointing to groups, datasets (and compound types). They 30 | /// differ from links in their ability to be stored and retrieved as data from the HDF5 31 | /// file in datasets themselves. 32 | /// 33 | class Reference { 34 | public: 35 | /// \brief Create an empty Reference to be initialized later 36 | Reference() = default; 37 | 38 | /// \brief Create a Reference to an object residing at a given location 39 | /// 40 | /// \param location A File or Group where the object being referenced to resides 41 | /// \param object A Dataset or Group to be referenced 42 | Reference(const Object& location, const Object& object); 43 | 44 | /// \brief Retrieve the Object being referenced by the Reference 45 | /// 46 | /// \tparam T the appropriate HighFive Container (either DataSet or Group) 47 | /// \param location the location where the referenced object is to be found (a File) 48 | /// \return the dereferenced Object (either a Group or DataSet) 49 | template 50 | T dereference(const Object& location) const; 51 | 52 | /// \brief Get only the type of the referenced Object 53 | /// 54 | /// \param location the location where the referenced object is to be found (a File) 55 | /// \return the ObjectType of the referenced object 56 | ObjectType getType(const Object& location) const; 57 | 58 | protected: 59 | /// \brief Create a Reference from a low-level HDF5 object reference 60 | inline explicit Reference(const hobj_ref_t h5_ref) 61 | : href(h5_ref) {}; 62 | 63 | /// \brief Create the low-level reference and store it at refptr 64 | /// 65 | /// \param refptr Pointer to a memory location where the created HDF5 reference will 66 | /// be stored 67 | void create_ref(hobj_ref_t* refptr) const; 68 | 69 | private: 70 | Object get_ref(const Object& location) const; 71 | 72 | hobj_ref_t href{}; 73 | std::string obj_name{}; 74 | hid_t parent_id{}; 75 | 76 | friend struct details::inspector; 77 | }; 78 | 79 | } // namespace HighFive 80 | 81 | #include "bits/H5Reference_misc.hpp" 82 | -------------------------------------------------------------------------------- /include/highfive/H5Selection.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include "H5DataSet.hpp" 12 | #include "H5DataSpace.hpp" 13 | #include "bits/H5Slice_traits.hpp" 14 | #include "bits/H5Friends.hpp" 15 | 16 | namespace HighFive { 17 | 18 | namespace detail { 19 | Selection make_selection(const DataSpace&, const DataSpace&, const DataSet&); 20 | } 21 | 22 | /// 23 | /// \brief Selection: represent a view on a slice/part of a dataset 24 | /// 25 | /// A Selection is valid only if its parent dataset is valid 26 | /// 27 | class Selection: public SliceTraits { 28 | public: 29 | /// 30 | /// \brief getSpace 31 | /// \return Dataspace associated with this selection 32 | /// 33 | DataSpace getSpace() const; 34 | 35 | /// 36 | /// \brief getMemSpace 37 | /// \return Dataspace associated with the memory representation of this 38 | /// selection 39 | /// 40 | DataSpace getMemSpace() const; 41 | 42 | /// 43 | /// \brief getDataSet 44 | /// \return parent dataset of this selection 45 | /// 46 | DataSet& getDataset(); 47 | const DataSet& getDataset() const; 48 | 49 | /// 50 | /// \brief return the datatype of the selection 51 | /// \return return the datatype of the selection 52 | const DataType getDataType() const; 53 | 54 | protected: 55 | Selection(const DataSpace& memspace, const DataSpace& file_space, const DataSet& set); 56 | 57 | private: 58 | DataSpace _mem_space, _file_space; 59 | DataSet _set; 60 | 61 | #if HIGHFIVE_HAS_FRIEND_DECLARATIONS 62 | template 63 | friend class ::HighFive::SliceTraits; 64 | #endif 65 | friend Selection detail::make_selection(const DataSpace&, const DataSpace&, const DataSet&); 66 | }; 67 | 68 | } // namespace HighFive 69 | -------------------------------------------------------------------------------- /include/highfive/H5Version.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #define HIGHFIVE_VERSION_MAJOR 3 12 | #define HIGHFIVE_VERSION_MINOR 0 13 | #define HIGHFIVE_VERSION_PATCH 0 14 | 15 | // Undefined for regular releases. 16 | #define HIGHFIVE_VERSION_PRERELEASE 2 17 | 18 | /** \brief Concatenated representation of the HighFive version. 19 | * 20 | * \warning The macro `HIGHFIVE_VERSION` by itself isn't valid C/C++. 21 | * 22 | * However, it can be stringified with two layers of macros, e.g., 23 | * \code{.cpp} 24 | * #define STRINGIFY_VALUE(s) STRINGIFY_NAME(s) 25 | * #define STRINGIFY_NAME(s) #s 26 | * 27 | * std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n"; 28 | * \endcode 29 | */ 30 | #define HIGHFIVE_VERSION 3.0.0 31 | 32 | /** \brief String representation of the HighFive version. 33 | * 34 | * \warning This macro only exists from 2.7.1 onwards. 35 | */ 36 | #define HIGHFIVE_VERSION_STRING "3.0.0-beta2" 37 | -------------------------------------------------------------------------------- /include/highfive/H5Version.hpp.in: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #define HIGHFIVE_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ 12 | #define HIGHFIVE_VERSION_MINOR @PROJECT_VERSION_MINOR@ 13 | #define HIGHFIVE_VERSION_PATCH @PROJECT_VERSION_PATCH@ 14 | 15 | // Undefined for regular releases. 16 | #define HIGHFIVE_VERSION_PRERELEASE @HIGHFIVE_VERSION_PRERELEASE@ 17 | 18 | /** \brief Concatenated representation of the HighFive version. 19 | * 20 | * \warning The macro `HIGHFIVE_VERSION` by itself isn't valid C/C++. 21 | * 22 | * However, it can be stringified with two layers of macros, e.g., 23 | * \code{.cpp} 24 | * #define STRINGIFY_VALUE(s) STRINGIFY_NAME(s) 25 | * #define STRINGIFY_NAME(s) #s 26 | * 27 | * std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n"; 28 | * \endcode 29 | */ 30 | #define HIGHFIVE_VERSION @PROJECT_VERSION@ 31 | 32 | /** \brief String representation of the HighFive version. 33 | * 34 | * \warning This macro only exists from 2.7.1 onwards. 35 | */ 36 | #define HIGHFIVE_VERSION_STRING "@PROJECT_VERSION@-beta@HIGHFIVE_VERSION_PRERELEASE@" 37 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Annotate_traits.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "../H5Attribute.hpp" 14 | 15 | namespace HighFive { 16 | 17 | template 18 | class AnnotateTraits { 19 | public: 20 | /// 21 | /// \brief create a new attribute with the name attribute_name 22 | /// \param attribute_name identifier of the attribute 23 | /// \param space Associated \ref DataSpace 24 | /// \param type 25 | /// \return the attribute object 26 | /// 27 | Attribute createAttribute(const std::string& attribute_name, 28 | const DataSpace& space, 29 | const DataType& type); 30 | 31 | /// 32 | /// \brief createAttribute create a new attribute on the current dataset with 33 | /// size specified by space 34 | /// \param attribute_name identifier of the attribute 35 | /// \param space Associated DataSpace 36 | /// informations 37 | /// \return Attribute Object 38 | template 39 | Attribute createAttribute(const std::string& attribute_name, const DataSpace& space); 40 | 41 | /// 42 | /// \brief createAttribute create a new attribute on the current dataset and 43 | /// write to it, inferring the DataSpace from data. 44 | /// \param attribute_name identifier of the attribute 45 | /// \param data Associated data to write, must support DataSpace::From, see 46 | /// \ref DataSpace for more information 47 | /// \return Attribute Object 48 | /// 49 | template 50 | Attribute createAttribute(const std::string& attribute_name, const T& data); 51 | 52 | /// 53 | /// \brief deleteAttribute let you delete an attribute by its name. 54 | /// \param attribute_name identifier of the attribute 55 | void deleteAttribute(const std::string& attribute_name); 56 | 57 | /// 58 | /// \brief open an existing attribute with the name attribute_name 59 | /// \param attribute_name identifier of the attribute 60 | /// \return the attribute object 61 | Attribute getAttribute(const std::string& attribute_name) const; 62 | 63 | /// 64 | /// \brief return the number of attributes of the node / group 65 | /// \return number of attributes 66 | size_t getNumberAttributes() const; 67 | 68 | /// 69 | /// \brief list all attribute name of the node / group 70 | /// \return number of attributes 71 | std::vector listAttributeNames() const; 72 | 73 | /// 74 | /// \brief checks an attribute exists 75 | /// \return number of attributes 76 | bool hasAttribute(const std::string& attr_name) const; 77 | 78 | private: 79 | using derivate_type = Derivate; 80 | }; 81 | } // namespace HighFive 82 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Annotate_traits_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include "H5Attribute_misc.hpp" 18 | #include "H5Iterables_misc.hpp" 19 | #include "h5a_wrapper.hpp" 20 | 21 | namespace HighFive { 22 | 23 | template 24 | inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, 25 | const DataSpace& space, 26 | const DataType& dtype) { 27 | auto attr_id = detail::h5a_create2(static_cast(this)->getId(), 28 | attribute_name.c_str(), 29 | dtype.getId(), 30 | space.getId(), 31 | H5P_DEFAULT, 32 | H5P_DEFAULT); 33 | return detail::make_attribute(attr_id); 34 | } 35 | 36 | template 37 | template 38 | inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, 39 | const DataSpace& space) { 40 | return createAttribute(attribute_name, space, create_and_check_datatype()); 41 | } 42 | 43 | template 44 | template 45 | inline Attribute AnnotateTraits::createAttribute(const std::string& attribute_name, 46 | const T& data) { 47 | Attribute att = 48 | createAttribute(attribute_name, 49 | DataSpace::From(data), 50 | create_and_check_datatype::base_type>()); 51 | att.write(data); 52 | return att; 53 | } 54 | 55 | template 56 | inline void AnnotateTraits::deleteAttribute(const std::string& attribute_name) { 57 | detail::h5a_delete(static_cast(this)->getId(), attribute_name.c_str()); 58 | } 59 | 60 | template 61 | inline Attribute AnnotateTraits::getAttribute(const std::string& attribute_name) const { 62 | const auto attr_id = detail::h5a_open(static_cast(this)->getId(), 63 | attribute_name.c_str(), 64 | H5P_DEFAULT); 65 | return detail::make_attribute(attr_id); 66 | } 67 | 68 | template 69 | inline size_t AnnotateTraits::getNumberAttributes() const { 70 | int res = detail::h5a_get_num_attrs(static_cast(this)->getId()); 71 | return static_cast(res); 72 | } 73 | 74 | template 75 | inline std::vector AnnotateTraits::listAttributeNames() const { 76 | std::vector names; 77 | details::HighFiveIterateData iterateData(names); 78 | 79 | size_t num_objs = getNumberAttributes(); 80 | names.reserve(num_objs); 81 | 82 | detail::h5a_iterate2(static_cast(this)->getId(), 83 | H5_INDEX_NAME, 84 | H5_ITER_INC, 85 | nullptr, 86 | &details::internal_high_five_iterate, 87 | static_cast(&iterateData)); 88 | 89 | return names; 90 | } 91 | 92 | template 93 | inline bool AnnotateTraits::hasAttribute(const std::string& attr_name) const { 94 | return detail::h5a_exists(static_cast(this)->getId(), attr_name.c_str()) > 0; 95 | } 96 | 97 | } // namespace HighFive 98 | -------------------------------------------------------------------------------- /include/highfive/bits/H5DataSet_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | 19 | #include "h5d_wrapper.hpp" 20 | #include "H5Utils.hpp" 21 | 22 | namespace HighFive { 23 | 24 | inline uint64_t DataSet::getStorageSize() const { 25 | if (!this->isValid()) { 26 | throw DataSetException("Invalid call to `DataSet::getStorageSize` for invalid object"); 27 | } 28 | 29 | return detail::h5d_get_storage_size(_hid); 30 | } 31 | 32 | inline DataType DataSet::getDataType() const { 33 | return DataType(detail::h5d_get_type(_hid)); 34 | } 35 | 36 | inline DataSpace DataSet::getSpace() const { 37 | DataSpace space; 38 | space._hid = detail::h5d_get_space(_hid); 39 | return space; 40 | } 41 | 42 | inline DataSpace DataSet::getMemSpace() const { 43 | return getSpace(); 44 | } 45 | 46 | inline uint64_t DataSet::getOffset() const { 47 | return static_cast(detail::h5d_get_offset(_hid)); 48 | } 49 | 50 | inline void DataSet::resize(const std::vector& dims) { 51 | const size_t numDimensions = getSpace().getDimensions().size(); 52 | if (dims.size() != numDimensions) { 53 | HDF5ErrMapper::ToException("Invalid dataspace dimensions, got " + 54 | std::to_string(dims.size()) + " expected " + 55 | std::to_string(numDimensions)); 56 | } 57 | 58 | std::vector real_dims(dims.begin(), dims.end()); 59 | detail::h5d_set_extent(getId(), real_dims.data()); 60 | } 61 | 62 | } // namespace HighFive 63 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Exception_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | #include "h5_wrapper.hpp" 15 | #include "h5e_wrapper.hpp" 16 | 17 | namespace HighFive { 18 | 19 | struct HDF5ErrMapper { 20 | template 21 | static inline herr_t stackWalk(unsigned n, const H5E_error2_t* err_desc, void* client_data) { 22 | auto** e_iter = static_cast(client_data); 23 | (void) n; 24 | 25 | const char* major_err = detail::nothrow::h5e_get_major(err_desc->maj_num); 26 | const char* minor_err = detail::nothrow::h5e_get_minor(err_desc->min_num); 27 | 28 | std::ostringstream oss; 29 | oss << '(' << major_err << ") " << minor_err; 30 | 31 | detail::nothrow::h5_free_memory((void*) major_err); 32 | detail::nothrow::h5_free_memory((void*) minor_err); 33 | 34 | auto* e = new ExceptionType(oss.str()); 35 | e->_err_major = err_desc->maj_num; 36 | e->_err_minor = err_desc->min_num; 37 | (*e_iter)->_next.reset(e); 38 | *e_iter = e; 39 | return 0; 40 | } 41 | 42 | template 43 | [[noreturn]] static inline void ToException(const std::string& prefix_msg) { 44 | hid_t err_stack = H5Eget_current_stack(); 45 | if (err_stack >= 0) { 46 | ExceptionType e(""); 47 | ExceptionType* e_iter = &e; 48 | 49 | detail::nothrow::h5e_walk2(err_stack, 50 | H5E_WALK_UPWARD, 51 | &HDF5ErrMapper::stackWalk, 52 | &e_iter); 53 | detail::nothrow::h5e_clear2(err_stack); 54 | 55 | const char* next_err_msg = (e.nextException() != NULL) ? (e.nextException()->what()) 56 | : (""); 57 | 58 | e.setErrorMsg(prefix_msg + " " + next_err_msg); 59 | throw e; 60 | } 61 | // throw generic error, unrecognized error 62 | throw ExceptionType(prefix_msg + ": Unknown HDF5 error"); 63 | } 64 | }; 65 | 66 | } // namespace HighFive 67 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Friends.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef HIGHFIVE_HAS_FRIEND_DECLARATIONS 4 | #ifdef _MSC_VER 5 | // This prevents a compiler bug on certain versions of MSVC. 6 | // Known to fail: Toolset 141. 7 | // See `CMakeLists.txt` for more information. 8 | #define HIGHFIVE_HAS_FRIEND_DECLARATIONS 1 9 | #endif 10 | #endif -------------------------------------------------------------------------------- /include/highfive/bits/H5Inspector_decl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "compute_total_size.hpp" 4 | 5 | namespace HighFive { 6 | 7 | template 8 | using unqualified_t = typename std::remove_const::type>::type; 9 | 10 | namespace details { 11 | 12 | template 13 | struct type_helper; 14 | 15 | template 16 | struct inspector; 17 | 18 | } // namespace details 19 | } // namespace HighFive 20 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Iterables_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | namespace HighFive { 18 | 19 | namespace details { 20 | 21 | // iterator for H5 iterate 22 | 23 | struct HighFiveIterateData { 24 | inline HighFiveIterateData(std::vector& my_names) 25 | : names(my_names) 26 | , err(NULL) {} 27 | 28 | std::vector& names; 29 | std::exception* err; 30 | 31 | inline void throwIfError() { 32 | if (err) { 33 | throw *err; 34 | } 35 | } 36 | }; 37 | 38 | template 39 | inline herr_t internal_high_five_iterate(hid_t /*id*/, 40 | const char* name, 41 | const InfoType* /*info*/, 42 | void* op_data) { 43 | auto* data = static_cast(op_data); 44 | try { 45 | data->names.emplace_back(name); 46 | return 0; 47 | } catch (...) { 48 | data->err = new ObjectException("Exception during H5Iterate, abort listing"); 49 | } 50 | return -1; 51 | } 52 | 53 | } // namespace details 54 | } // namespace HighFive 55 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Object_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "../H5Exception.hpp" 14 | #include "../H5Utility.hpp" 15 | #include "h5i_wrapper.hpp" 16 | 17 | namespace HighFive { 18 | 19 | inline Object::Object() 20 | : _hid(H5I_INVALID_HID) {} 21 | 22 | inline Object::Object(hid_t hid) 23 | : _hid(hid) {} 24 | 25 | inline Object::Object(const Object& other) 26 | : _hid(other._hid) { 27 | if (other.isValid()) { 28 | detail::h5i_inc_ref(_hid); 29 | } 30 | } 31 | 32 | inline Object::Object(Object&& other) noexcept 33 | : _hid(other._hid) { 34 | other._hid = H5I_INVALID_HID; 35 | } 36 | 37 | inline Object& Object::operator=(const Object& other) { 38 | if (this != &other) { 39 | if ((*this).isValid()) { 40 | detail::h5i_dec_ref(_hid); 41 | } 42 | 43 | _hid = other._hid; 44 | if (other.isValid()) { 45 | detail::h5i_inc_ref(_hid); 46 | } 47 | } 48 | return *this; 49 | } 50 | 51 | inline Object::~Object() { 52 | if (isValid()) { 53 | if (detail::nothrow::h5i_dec_ref(_hid) < 0) { 54 | HIGHFIVE_LOG_ERROR("Failed to decrease reference count of HID"); 55 | } 56 | } 57 | } 58 | 59 | inline bool Object::isValid() const noexcept { 60 | return (_hid > 0) && (detail::nothrow::h5i_is_valid(_hid) > 0); 61 | } 62 | 63 | inline hid_t Object::getId() const noexcept { 64 | return _hid; 65 | } 66 | 67 | static inline ObjectType _convert_object_type(const H5I_type_t& h5type) { 68 | switch (h5type) { 69 | case H5I_FILE: 70 | return ObjectType::File; 71 | case H5I_GROUP: 72 | return ObjectType::Group; 73 | case H5I_DATATYPE: 74 | return ObjectType::UserDataType; 75 | case H5I_DATASPACE: 76 | return ObjectType::DataSpace; 77 | case H5I_DATASET: 78 | return ObjectType::Dataset; 79 | case H5I_ATTR: 80 | return ObjectType::Attribute; 81 | default: 82 | return ObjectType::Other; 83 | } 84 | } 85 | 86 | inline ObjectType Object::getType() const { 87 | // H5Iget_type is a very lightweight func which extracts the type from the id 88 | return _convert_object_type(detail::h5i_get_type(_hid)); 89 | } 90 | 91 | inline ObjectInfo Object::getInfo() const { 92 | ObjectInfo info; 93 | #if (H5Oget_info_vers < 3) 94 | if (H5Oget_info(_hid, &info.raw_info) < 0) { 95 | #else 96 | if (H5Oget_info1(_hid, &info.raw_info) < 0) { 97 | #endif 98 | HDF5ErrMapper::ToException("Unable to obtain info for object"); 99 | } 100 | return info; 101 | } 102 | 103 | inline haddr_t ObjectInfo::getAddress() const noexcept { 104 | return raw_info.addr; 105 | } 106 | inline size_t ObjectInfo::getRefCount() const noexcept { 107 | return raw_info.rc; 108 | } 109 | inline time_t ObjectInfo::getCreationTime() const noexcept { 110 | return raw_info.btime; 111 | } 112 | inline time_t ObjectInfo::getModificationTime() const noexcept { 113 | return raw_info.mtime; 114 | } 115 | 116 | 117 | } // namespace HighFive 118 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Path_traits.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020, EPFL - Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include "H5_definitions.hpp" 12 | 13 | namespace HighFive { 14 | 15 | template 16 | class PathTraits { 17 | public: 18 | PathTraits(); 19 | 20 | /// 21 | /// \brief return the path to the current object 22 | /// \return the path to the object 23 | std::string getPath() const; 24 | 25 | /// 26 | /// \brief Return a reference to the File object this object belongs 27 | /// \return the File object ref 28 | File& getFile() const; 29 | 30 | protected: 31 | std::shared_ptr _file_obj; // keep a ref to file so we keep its ref count > 0 32 | }; 33 | 34 | } // namespace HighFive 35 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Path_traits_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020, EPFL - Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | 13 | #include "H5Utils.hpp" 14 | #include "H5Path_traits.hpp" 15 | 16 | namespace HighFive { 17 | 18 | template 19 | inline PathTraits::PathTraits() { 20 | static_assert(std::is_same::value || std::is_same::value || 21 | std::is_same::value, 22 | "PathTraits can only be applied to Group, DataSet and Attribute"); 23 | const auto& obj = static_cast(*this); 24 | if (obj.isValid()) { 25 | const hid_t file_id = detail::h5i_get_file_id(obj.getId()); 26 | _file_obj.reset(new File(file_id)); 27 | } 28 | } 29 | 30 | template 31 | inline std::string PathTraits::getPath() const { 32 | return details::get_name([this](char* buffer, size_t length) { 33 | return detail::h5i_get_name(static_cast(*this).getId(), buffer, length); 34 | }); 35 | } 36 | 37 | template 38 | inline File& PathTraits::getFile() const { 39 | const auto& obj = static_cast(*this); 40 | if (!obj.isValid()) { 41 | throw ObjectException("Invalid call to `PathTraits::getFile` for invalid object"); 42 | } 43 | return *_file_obj; 44 | } 45 | 46 | } // namespace HighFive 47 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Reference_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020, EPFL - Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #pragma once 11 | 12 | #include 13 | #include 14 | 15 | #include "H5Utils.hpp" 16 | 17 | #include "../H5Object.hpp" 18 | 19 | #include "h5r_wrapper.hpp" 20 | 21 | namespace HighFive { 22 | 23 | inline Reference::Reference(const Object& location, const Object& object) 24 | : parent_id(location.getId()) { 25 | obj_name = details::get_name([&](char* buffer, size_t length) { 26 | return detail::h5i_get_name(object.getId(), buffer, length); 27 | }); 28 | } 29 | 30 | inline void Reference::create_ref(hobj_ref_t* refptr) const { 31 | detail::h5r_create(refptr, parent_id, obj_name.c_str(), H5R_OBJECT, -1); 32 | } 33 | 34 | inline ObjectType Reference::getType(const Object& location) const { 35 | return get_ref(location).getType(); 36 | } 37 | 38 | template 39 | inline T Reference::dereference(const Object& location) const { 40 | static_assert(std::is_same::value || std::is_same::value, 41 | "We can only (de)reference HighFive::Group or HighFive:DataSet"); 42 | auto obj = get_ref(location); 43 | if (obj.getType() != T::type) { 44 | HDF5ErrMapper::ToException("Trying to dereference the wrong type"); 45 | } 46 | #if defined __GNUC__ && __GNUC__ < 9 47 | return std::move(obj); 48 | #else 49 | return obj; 50 | #endif 51 | } 52 | 53 | inline Object Reference::get_ref(const Object& location) const { 54 | #if (H5Rdereference_vers == 2) 55 | hid_t res = detail::h5r_dereference(location.getId(), H5P_DEFAULT, H5R_OBJECT, &href); 56 | #else 57 | hid_t res = detail::h5r_dereference(location.getId(), H5R_OBJECT, &href); 58 | #endif 59 | return Object(res); 60 | } 61 | 62 | } // namespace HighFive 63 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Selection_misc.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | namespace HighFive { 12 | 13 | inline Selection::Selection(const DataSpace& memspace, 14 | const DataSpace& file_space, 15 | const DataSet& set) 16 | : _mem_space(memspace) 17 | , _file_space(file_space) 18 | , _set(set) {} 19 | 20 | inline DataSpace Selection::getSpace() const { 21 | return _file_space; 22 | } 23 | 24 | inline DataSpace Selection::getMemSpace() const { 25 | return _mem_space; 26 | } 27 | 28 | inline DataSet& Selection::getDataset() { 29 | return _set; 30 | } 31 | 32 | inline const DataSet& Selection::getDataset() const { 33 | return _set; 34 | } 35 | 36 | // Not only a shortcut but also for templated compat with H5Dataset 37 | inline const DataType Selection::getDataType() const { 38 | return _set.getDataType(); 39 | } 40 | 41 | namespace detail { 42 | inline Selection make_selection(const DataSpace& mem_space, 43 | const DataSpace& file_space, 44 | const DataSet& set) { 45 | return Selection(mem_space, file_space, set); 46 | } 47 | } // namespace detail 48 | 49 | } // namespace HighFive 50 | -------------------------------------------------------------------------------- /include/highfive/bits/H5Utils.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | // internal utilities functions 12 | #include 13 | #include 14 | #include // __GLIBCXX__ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "../H5Exception.hpp" 24 | #include "H5Friends.hpp" 25 | 26 | namespace HighFive { 27 | 28 | namespace details { 29 | // converter function for hsize_t -> size_t when hsize_t != size_t 30 | template 31 | inline std::vector to_vector_size_t(const std::vector& vec) { 32 | static_assert(std::is_same::value == false, 33 | " hsize_t != size_t mandatory here"); 34 | std::vector res(vec.size()); 35 | std::transform(vec.cbegin(), vec.cend(), res.begin(), [](Size e) { 36 | return static_cast(e); 37 | }); 38 | return res; 39 | } 40 | 41 | // converter function for hsize_t -> size_t when size_t == hsize_t 42 | inline std::vector to_vector_size_t(const std::vector& vec) { 43 | return vec; 44 | } 45 | 46 | // read name from a H5 object using the specified function 47 | template 48 | inline std::string get_name(T fct) { 49 | const size_t maxLength = 255; 50 | char buffer[maxLength + 1]; 51 | ssize_t retcode = fct(buffer, static_cast(maxLength) + 1); 52 | if (retcode < 0) { 53 | HDF5ErrMapper::ToException("Error accessing object name"); 54 | } 55 | const size_t length = static_cast(retcode); 56 | if (length <= maxLength) { 57 | return std::string(buffer, length); 58 | } 59 | std::vector bigBuffer(length + 1, 0); 60 | fct(bigBuffer.data(), length + 1); 61 | return std::string(bigBuffer.data(), length); 62 | } 63 | 64 | template 65 | inline std::string format_vector(const Container& container) { 66 | auto sout = std::stringstream{}; 67 | 68 | sout << "[ "; 69 | for (size_t i = 0; i < container.size(); ++i) { 70 | sout << container[i] << (i == container.size() - 1 ? "" : ", "); 71 | } 72 | sout << "]"; 73 | 74 | return sout.str(); 75 | } 76 | 77 | } // namespace details 78 | } // namespace HighFive 79 | -------------------------------------------------------------------------------- /include/highfive/bits/H5_definitions.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(__GNUC__) || defined(__clang__) 4 | #define H5_DEPRECATED(msg) __attribute__((deprecated(#msg))) 5 | #elif defined(_MSC_VER) 6 | #define H5_DEPRECATED(msg) __declspec(deprecated(#msg)) 7 | #else 8 | #pragma message("WARNING: Compiler doesn't support deprecation") 9 | #define H5_DEPRECATED(msg) 10 | #endif 11 | 12 | // Forward declarations 13 | 14 | namespace HighFive { 15 | 16 | enum class LinkType; 17 | enum class ObjectType; 18 | enum class PropertyType; 19 | 20 | class Attribute; 21 | class DataSet; 22 | class DataSpace; 23 | class DataType; 24 | class Exception; 25 | class File; 26 | class FileDriver; 27 | class Group; 28 | class Object; 29 | class ObjectInfo; 30 | class Reference; 31 | class Selection; 32 | class SilenceHDF5; 33 | 34 | template 35 | class AtomicType; 36 | 37 | template 38 | class AnnotateTraits; 39 | 40 | template 41 | class NodeTraits; 42 | 43 | template 44 | class PropertyList; 45 | 46 | } // namespace HighFive 47 | -------------------------------------------------------------------------------- /include/highfive/bits/assert_compatible_spaces.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2024, BlueBrain Project, EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include "../H5Exception.hpp" 13 | #include "../H5DataSpace.hpp" 14 | 15 | namespace HighFive { 16 | namespace detail { 17 | 18 | inline void assert_compatible_spaces(const DataSpace& old, const std::vector& dims) { 19 | auto n_elements_old = old.getElementCount(); 20 | auto n_elements_new = dims.size() == 0 ? 1 : compute_total_size(dims); 21 | 22 | if (n_elements_old != n_elements_new) { 23 | throw Exception("Invalid parameter `new_dims` number of elements differ: " + 24 | std::to_string(n_elements_old) + " (old) vs. " + 25 | std::to_string(n_elements_new) + " (new)"); 26 | } 27 | } 28 | } // namespace detail 29 | } // namespace HighFive 30 | -------------------------------------------------------------------------------- /include/highfive/bits/compute_total_size.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | namespace HighFive { 9 | 10 | inline size_t compute_total_size(const std::vector& dims) { 11 | return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies()); 12 | } 13 | 14 | } // namespace HighFive 15 | -------------------------------------------------------------------------------- /include/highfive/bits/convert_size_vector.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * Copyright (c), 2017-2024, BlueBrain Project, EPFL 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. 6 | * (See accompanying file LICENSE_1_0.txt or copy at 7 | * http://www.boost.org/LICENSE_1_0.txt) 8 | * 9 | */ 10 | #pragma once 11 | 12 | #include 13 | 14 | namespace HighFive { 15 | namespace detail { 16 | 17 | template 18 | inline std::vector convertSizeVector(const It& begin, const It& end) { 19 | std::vector to(static_cast(end - begin)); 20 | std::copy(begin, end, to.begin()); 21 | 22 | return to; 23 | } 24 | 25 | template 26 | inline std::vector convertSizeVector(const std::vector& from) { 27 | return convertSizeVector(from.cbegin(), from.cend()); 28 | } 29 | 30 | } // namespace detail 31 | } // namespace HighFive 32 | -------------------------------------------------------------------------------- /include/highfive/bits/h5_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace HighFive { 5 | namespace detail { 6 | inline void h5_free_memory(void* mem) { 7 | if (H5free_memory(mem) < 0) { 8 | throw DataTypeException("Could not free memory allocated by HDF5"); 9 | } 10 | } 11 | 12 | namespace nothrow { 13 | inline herr_t h5_free_memory(void* mem) { 14 | return H5free_memory(mem); 15 | } 16 | } // namespace nothrow 17 | 18 | } // namespace detail 19 | } // namespace HighFive 20 | -------------------------------------------------------------------------------- /include/highfive/bits/h5e_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace HighFive { 5 | namespace detail { 6 | namespace nothrow { 7 | 8 | 9 | inline void h5e_get_auto2(hid_t estack_id, H5E_auto2_t* func, void** client_data) { 10 | H5Eget_auto2(estack_id, func, client_data); 11 | } 12 | 13 | inline void h5e_set_auto2(hid_t estack_id, H5E_auto2_t func, void* client_data) { 14 | H5Eset_auto2(estack_id, func, client_data); 15 | } 16 | 17 | inline char* h5e_get_major(H5E_major_t maj) { 18 | return H5Eget_major(maj); 19 | } 20 | 21 | inline char* h5e_get_minor(H5E_minor_t min) { 22 | return H5Eget_minor(min); 23 | } 24 | 25 | inline herr_t h5e_walk2(hid_t err_stack, 26 | H5E_direction_t direction, 27 | H5E_walk2_t func, 28 | void* client_data) { 29 | return H5Ewalk2(err_stack, direction, func, client_data); 30 | } 31 | 32 | inline herr_t h5e_clear2(hid_t err_stack) { 33 | return H5Eclear2(err_stack); 34 | } 35 | 36 | 37 | } // namespace nothrow 38 | } // namespace detail 39 | } // namespace HighFive 40 | -------------------------------------------------------------------------------- /include/highfive/bits/h5f_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace HighFive { 5 | namespace detail { 6 | namespace nothrow { 7 | inline hid_t h5f_open(const char* filename, unsigned flags, hid_t fapl_id) { 8 | return H5Fopen(filename, flags, fapl_id); 9 | } 10 | } // namespace nothrow 11 | 12 | inline hid_t h5f_create(const char* filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id) { 13 | hid_t file_id = H5Fcreate(filename, flags, fcpl_id, fapl_id); 14 | 15 | if (file_id == H5I_INVALID_HID) { 16 | HDF5ErrMapper::ToException(std::string("Failed to create file ") + filename); 17 | } 18 | return file_id; 19 | } 20 | 21 | inline ssize_t h5f_get_name(hid_t obj_id, char* name, size_t size) { 22 | ssize_t nread = H5Fget_name(obj_id, name, size); 23 | if (nread < 0) { 24 | HDF5ErrMapper::ToException(std::string("Failed to get file from id")); 25 | } 26 | 27 | return nread; 28 | } 29 | 30 | inline herr_t h5f_flush(hid_t object_id, H5F_scope_t scope) { 31 | herr_t err = H5Fflush(object_id, scope); 32 | if (err < 0) { 33 | HDF5ErrMapper::ToException(std::string("Failed to flush file")); 34 | } 35 | 36 | return err; 37 | } 38 | 39 | inline herr_t h5f_get_filesize(hid_t file_id, hsize_t* size) { 40 | herr_t err = H5Fget_filesize(file_id, size); 41 | if (err < 0) { 42 | HDF5ErrMapper::ToException(std::string("Unable to retrieve size of file")); 43 | } 44 | 45 | return err; 46 | } 47 | 48 | inline hssize_t h5f_get_freespace(hid_t file_id) { 49 | hssize_t free_space = H5Fget_freespace(file_id); 50 | if (free_space < 0) { 51 | HDF5ErrMapper::ToException( 52 | std::string("Unable to retrieve unused space of file ")); 53 | } 54 | return free_space; 55 | } 56 | 57 | } // namespace detail 58 | } // namespace HighFive 59 | -------------------------------------------------------------------------------- /include/highfive/bits/h5g_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | namespace HighFive { 9 | namespace detail { 10 | 11 | inline hid_t h5g_create2(hid_t loc_id, 12 | const char* name, 13 | hid_t lcpl_id, 14 | hid_t gcpl_id, 15 | hid_t gapl_id) { 16 | hid_t group_id = H5Gcreate2(loc_id, name, lcpl_id, gcpl_id, gapl_id); 17 | if (group_id == H5I_INVALID_HID) { 18 | HDF5ErrMapper::ToException(std::string("Unable to create the group \"") + 19 | name + "\":"); 20 | } 21 | 22 | return group_id; 23 | } 24 | 25 | inline hid_t h5g_open2(hid_t loc_id, const char* name, hid_t gapl_id) { 26 | hid_t group_id = H5Gopen2(loc_id, name, gapl_id); 27 | if (group_id == H5I_INVALID_HID) { 28 | HDF5ErrMapper::ToException(std::string("Unable to open the group \"") + 29 | name + "\":"); 30 | } 31 | return group_id; 32 | } 33 | 34 | inline herr_t h5g_get_num_objs(hid_t loc_id, hsize_t* num_objs) { 35 | herr_t err = H5Gget_num_objs(loc_id, num_objs); 36 | if (err < 0) { 37 | HDF5ErrMapper::ToException( 38 | std::string("Unable to count objects in existing group or file")); 39 | } 40 | 41 | return err; 42 | } 43 | 44 | 45 | } // namespace detail 46 | } // namespace HighFive 47 | -------------------------------------------------------------------------------- /include/highfive/bits/h5i_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HighFive { 6 | namespace detail { 7 | inline int h5i_inc_ref(hid_t id) { 8 | auto count = H5Iinc_ref(id); 9 | 10 | if (count < 0) { 11 | throw ObjectException("Failed to increase reference count of HID"); 12 | } 13 | 14 | return count; 15 | } 16 | 17 | namespace nothrow { 18 | 19 | inline int h5i_dec_ref(hid_t id) { 20 | return H5Idec_ref(id); 21 | } 22 | 23 | } // namespace nothrow 24 | 25 | inline int h5i_dec_ref(hid_t id) { 26 | int count = H5Idec_ref(id); 27 | if (count < 0) { 28 | throw ObjectException("Failed to decrease reference count of HID"); 29 | } 30 | 31 | return count; 32 | } 33 | 34 | namespace nothrow { 35 | inline htri_t h5i_is_valid(hid_t id) { 36 | return H5Iis_valid(id); 37 | } 38 | 39 | } // namespace nothrow 40 | 41 | inline htri_t h5i_is_valid(hid_t id) { 42 | htri_t tri = H5Iis_valid(id); 43 | if (tri < 0) { 44 | throw ObjectException("Failed to check if HID is valid"); 45 | } 46 | 47 | return tri; 48 | } 49 | 50 | inline H5I_type_t h5i_get_type(hid_t id) { 51 | H5I_type_t type = H5Iget_type(id); 52 | if (type == H5I_BADID) { 53 | HDF5ErrMapper::ToException("Failed to get type of HID"); 54 | } 55 | 56 | return type; 57 | } 58 | 59 | template 60 | inline hid_t h5i_get_file_id(hid_t id) { 61 | hid_t file_id = H5Iget_file_id(id); 62 | if (file_id < 0) { 63 | HDF5ErrMapper::ToException("Failed not obtain file HID of object"); 64 | } 65 | 66 | return file_id; 67 | } 68 | 69 | inline ssize_t h5i_get_name(hid_t id, char* name, size_t size) { 70 | ssize_t n_chars = H5Iget_name(id, name, size); 71 | if (n_chars < 0) { 72 | HDF5ErrMapper::ToException("Failed to get name of HID."); 73 | } 74 | 75 | return n_chars; 76 | } 77 | 78 | } // namespace detail 79 | } // namespace HighFive 80 | -------------------------------------------------------------------------------- /include/highfive/bits/h5o_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace HighFive { 7 | namespace detail { 8 | 9 | inline hid_t h5o_open(hid_t loc_id, const char* name, hid_t lapl_id) { 10 | hid_t hid = H5Oopen(loc_id, name, lapl_id); 11 | if (hid < 0) { 12 | HDF5ErrMapper::ToException(std::string("Unable to open \"") + name + "\":"); 13 | } 14 | 15 | return hid; 16 | } 17 | 18 | inline herr_t h5o_close(hid_t id) { 19 | herr_t err = H5Oclose(id); 20 | if (err < 0) { 21 | HDF5ErrMapper::ToException("Unable to close object."); 22 | } 23 | 24 | return err; 25 | } 26 | 27 | } // namespace detail 28 | } // namespace HighFive 29 | -------------------------------------------------------------------------------- /include/highfive/bits/h5r_wrapper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HighFive { 6 | namespace detail { 7 | inline herr_t h5r_create(void* ref, 8 | hid_t loc_id, 9 | const char* name, 10 | H5R_type_t ref_type, 11 | hid_t space_id) { 12 | herr_t err = H5Rcreate(ref, loc_id, name, ref_type, space_id); 13 | if (err < 0) { 14 | HDF5ErrMapper::ToException( 15 | std::string("Unable to create the reference for \"") + name + "\":"); 16 | } 17 | 18 | return err; 19 | } 20 | 21 | #if (H5Rdereference_vers == 2) 22 | inline hid_t h5r_dereference(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, const void* ref) { 23 | hid_t hid = H5Rdereference(obj_id, oapl_id, ref_type, ref); 24 | if (hid < 0) { 25 | HDF5ErrMapper::ToException("Unable to dereference."); 26 | } 27 | 28 | return hid; 29 | } 30 | #else 31 | inline hid_t h5r_dereference(hid_t dataset, H5R_type_t ref_type, const void* ref) { 32 | hid_t hid = H5Rdereference(dataset, ref_type, ref); 33 | if (hid < 0) { 34 | HDF5ErrMapper::ToException("Unable to dereference."); 35 | } 36 | 37 | return hid; 38 | } 39 | #endif 40 | 41 | } // namespace detail 42 | } // namespace HighFive 43 | -------------------------------------------------------------------------------- /include/highfive/bits/inspector_stl_span_misc.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "H5Inspector_decl.hpp" 4 | #include "../H5Exception.hpp" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | namespace HighFive { 11 | namespace details { 12 | 13 | 14 | // Anything with the same API as `std::span` can implemented by inheriting from 15 | // this class. 16 | template 17 | struct inspector_stl_span { 18 | using type = Span; 19 | using value_type = unqualified_t; 20 | using base_type = typename inspector::base_type; 21 | using hdf5_type = typename inspector::hdf5_type; 22 | 23 | static constexpr size_t ndim = 1; 24 | static constexpr size_t min_ndim = ndim + inspector::min_ndim; 25 | static constexpr size_t max_ndim = ndim + inspector::max_ndim; 26 | 27 | static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && 28 | inspector::is_trivially_nestable; 29 | static constexpr bool is_trivially_nestable = false; 30 | 31 | 32 | static size_t getRank(const type& val) { 33 | if (!val.empty()) { 34 | return ndim + inspector::getRank(val[0]); 35 | } else { 36 | return min_ndim; 37 | } 38 | } 39 | 40 | static std::vector getDimensions(const type& val) { 41 | auto rank = getRank(val); 42 | std::vector sizes(rank, 1ul); 43 | sizes[0] = val.size(); 44 | if (!val.empty()) { 45 | auto s = inspector::getDimensions(val[0]); 46 | assert(s.size() + ndim == sizes.size()); 47 | for (size_t i = 0; i < s.size(); ++i) { 48 | sizes[i + ndim] = s[i]; 49 | } 50 | } 51 | return sizes; 52 | } 53 | 54 | static void prepare(type& val, const std::vector& expected_dims) { 55 | auto actual_dims = getDimensions(val); 56 | if (actual_dims.size() != expected_dims.size()) { 57 | throw DataSpaceException("Mismatching rank."); 58 | } 59 | 60 | for (size_t i = 0; i < actual_dims.size(); ++i) { 61 | if (actual_dims[i] != expected_dims[i]) { 62 | throw DataSpaceException("Mismatching dimensions."); 63 | } 64 | } 65 | } 66 | 67 | static hdf5_type* data(type& val) { 68 | return val.empty() ? nullptr : inspector::data(val[0]); 69 | } 70 | 71 | static const hdf5_type* data(const type& val) { 72 | return val.empty() ? nullptr : inspector::data(val[0]); 73 | } 74 | 75 | template 76 | static void serialize(const type& val, const std::vector& dims, It m) { 77 | if (!val.empty()) { 78 | auto subdims = std::vector(dims.begin() + ndim, dims.end()); 79 | size_t subsize = compute_total_size(subdims); 80 | for (const auto& e: val) { 81 | inspector::serialize(e, subdims, m); 82 | m += subsize; 83 | } 84 | } 85 | } 86 | 87 | template 88 | static void unserialize(const It& vec_align, const std::vector& dims, type& val) { 89 | std::vector subdims(dims.begin() + ndim, dims.end()); 90 | size_t subsize = compute_total_size(subdims); 91 | for (size_t i = 0; i < dims[0]; ++i) { 92 | inspector::unserialize(vec_align + i * subsize, subdims, val[i]); 93 | } 94 | } 95 | }; 96 | 97 | } // namespace details 98 | } // namespace HighFive 99 | -------------------------------------------------------------------------------- /include/highfive/bits/squeeze.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2024, BlueBrain Project, EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include 12 | #include "../H5Exception.hpp" 13 | 14 | namespace HighFive { 15 | namespace detail { 16 | 17 | /// \brief Squeeze `axes` from `dims`. 18 | /// 19 | /// An axis can only be squeezed if it's dimension is `1`. The elements of 20 | /// `axes` must be in the range `0, ..., dims.size()` (exclusive) and don't 21 | /// have to be sorted. 22 | /// 23 | /// Example: 24 | /// squeeze({1, 3, 2, 1}, {0, 3}) == {3, 2} 25 | inline std::vector squeeze(const std::vector& dims, 26 | const std::vector& axes) { 27 | auto n_dims = dims.size(); 28 | auto mask = std::vector(n_dims, false); 29 | for (size_t i = 0; i < axes.size(); ++i) { 30 | if (axes[i] >= n_dims) { 31 | throw Exception("Out of range: axes[" + std::to_string(i) + 32 | "] == " + std::to_string(axes[i]) + " >= " + std::to_string(n_dims)); 33 | } 34 | 35 | mask[axes[i]] = true; 36 | } 37 | 38 | auto squeezed_dims = std::vector{}; 39 | for (size_t i = 0; i < n_dims; ++i) { 40 | if (!mask[i]) { 41 | squeezed_dims.push_back(dims[i]); 42 | } else { 43 | if (dims[i] != 1) { 44 | throw Exception("Squeezing non-unity axis: axes[" + std::to_string(i) + 45 | "] = " + std::to_string(axes[i])); 46 | } 47 | } 48 | } 49 | 50 | return squeezed_dims; 51 | } 52 | 53 | } // namespace detail 54 | } // namespace HighFive 55 | -------------------------------------------------------------------------------- /include/highfive/bits/string_padding.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HighFive { 6 | 7 | enum class StringPadding : std::underlying_type::type { 8 | NullTerminated = H5T_STR_NULLTERM, 9 | NullPadded = H5T_STR_NULLPAD, 10 | SpacePadded = H5T_STR_SPACEPAD 11 | }; 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /include/highfive/bits/xtensor_header_version.hpp: -------------------------------------------------------------------------------- 1 | // clang-format off 2 | #if HIGHFIVE_XTENSOR_HEADER_VERSION == 0 3 | #if __cplusplus >= 201703L 4 | #if __has_include() 5 | #define HIGHFIVE_XTENSOR_HEADER_VERSION 1 6 | #elif __has_include() 7 | #define HIGHFIVE_XTENSOR_HEADER_VERSION 2 8 | #else 9 | #error "Unable to guess HIGHFIVE_XTENSOR_HEADER_VERSION. Please set manually." 10 | #endif 11 | #elif __cplusplus == 201402L 12 | // XTensor 0.26 and newer require C++17. Hence, if we have C++14, only 13 | // `HIGHFIVE_XTENSOR_HEADER_VERSION == 1` makes sense. 14 | #define HIGHFIVE_XTENSOR_HEADER_VERSION 1 15 | #elif defined(_MSC_VER) && __cplusplus == 199711L 16 | #error \ 17 | "Use /Zc:__cplusplus to make MSVC set __cplusplus correctly or HIGHFIVE_XTENSOR_HEADER_VERSION to skip xtensor version deduction." 18 | #else 19 | #error "HighFive requires C++14 or newer." 20 | #endif 21 | #endif 22 | // clang-format on 23 | -------------------------------------------------------------------------------- /include/highfive/boost.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "boost_ublas.hpp" 4 | #include "boost_multi_array.hpp" 5 | -------------------------------------------------------------------------------- /include/highfive/boost_span.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "bits/H5Inspector_decl.hpp" 4 | #include "H5Exception.hpp" 5 | #include "bits/inspector_stl_span_misc.hpp" 6 | 7 | #include 8 | 9 | namespace HighFive { 10 | namespace details { 11 | template 12 | struct inspector>: public inspector_stl_span> { 13 | private: 14 | using super = inspector_stl_span>; 15 | 16 | public: 17 | using type = typename super::type; 18 | using value_type = typename super::value_type; 19 | using base_type = typename super::base_type; 20 | using hdf5_type = typename super::hdf5_type; 21 | }; 22 | 23 | } // namespace details 24 | } // namespace HighFive 25 | -------------------------------------------------------------------------------- /include/highfive/boost_ublas.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "bits/H5Inspector_decl.hpp" 4 | #include "H5Exception.hpp" 5 | 6 | #include 7 | 8 | namespace HighFive { 9 | namespace details { 10 | 11 | template 12 | struct inspector> { 13 | using type = boost::numeric::ublas::matrix; 14 | using value_type = unqualified_t; 15 | using base_type = typename inspector::base_type; 16 | using hdf5_type = typename inspector::hdf5_type; 17 | 18 | static constexpr size_t ndim = 2; 19 | static constexpr size_t min_ndim = ndim + inspector::min_ndim; 20 | static constexpr size_t max_ndim = ndim + inspector::max_ndim; 21 | 22 | static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && 23 | inspector::is_trivially_copyable; 24 | static constexpr bool is_trivially_nestable = false; 25 | 26 | static size_t getRank(const type& val) { 27 | return ndim + inspector::getRank(val(0, 0)); 28 | } 29 | 30 | static std::vector getDimensions(const type& val) { 31 | std::vector sizes{val.size1(), val.size2()}; 32 | auto s = inspector::getDimensions(val(0, 0)); 33 | sizes.insert(sizes.end(), s.begin(), s.end()); 34 | return sizes; 35 | } 36 | 37 | static void prepare(type& val, const std::vector& dims) { 38 | if (dims.size() < ndim) { 39 | std::ostringstream os; 40 | os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim 41 | << " boost::numeric::ublas::matrix"; 42 | throw DataSpaceException(os.str()); 43 | } 44 | val.resize(dims[0], dims[1], false); 45 | } 46 | 47 | static hdf5_type* data(type& val) { 48 | return inspector::data(val(0, 0)); 49 | } 50 | 51 | static const hdf5_type* data(const type& val) { 52 | return inspector::data(val(0, 0)); 53 | } 54 | 55 | static void serialize(const type& val, const std::vector& dims, hdf5_type* m) { 56 | size_t size = val.size1() * val.size2(); 57 | auto subdims = std::vector(dims.begin() + ndim, dims.end()); 58 | size_t subsize = compute_total_size(subdims); 59 | for (size_t i = 0; i < size; ++i) { 60 | inspector::serialize(*(&val(0, 0) + i), subdims, m + i * subsize); 61 | } 62 | } 63 | 64 | static void unserialize(const hdf5_type* vec_align, 65 | const std::vector& dims, 66 | type& val) { 67 | std::vector next_dims(dims.begin() + ndim, dims.end()); 68 | size_t subsize = compute_total_size(next_dims); 69 | size_t size = val.size1() * val.size2(); 70 | for (size_t i = 0; i < size; ++i) { 71 | inspector::unserialize(vec_align + i * subsize, 72 | next_dims, 73 | *(&val(0, 0) + i)); 74 | } 75 | } 76 | }; 77 | 78 | } // namespace details 79 | } // namespace HighFive 80 | -------------------------------------------------------------------------------- /include/highfive/h5easy_bits/H5Easy_scalar.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include "../H5Easy.hpp" 12 | #include "H5Easy_misc.hpp" 13 | #include "default_io_impl.hpp" 14 | 15 | namespace H5Easy { 16 | 17 | namespace detail { 18 | 19 | /* 20 | Base template for partial specialization: the fallback if specialized templates don't match. 21 | Used e.g. for scalars. 22 | */ 23 | template 24 | struct io_impl: public default_io_impl { 25 | inline static DataSet dump_extend(File& file, 26 | const std::string& path, 27 | const T& data, 28 | const std::vector& idx, 29 | const DumpOptions& options) { 30 | std::vector ones(idx.size(), 1); 31 | 32 | if (file.exist(path)) { 33 | DataSet dataset = file.getDataSet(path); 34 | std::vector dims = dataset.getDimensions(); 35 | std::vector shape = dims; 36 | if (dims.size() != idx.size()) { 37 | throw detail::error( 38 | file, 39 | path, 40 | "H5Easy::dump: Dimension of the index and the existing field do not match"); 41 | } 42 | for (size_t i = 0; i < dims.size(); ++i) { 43 | shape[i] = std::max(dims[i], idx[i] + 1); 44 | } 45 | if (shape != dims) { 46 | dataset.resize(shape); 47 | } 48 | dataset.select(idx, ones).write(data); 49 | if (options.flush()) { 50 | file.flush(); 51 | } 52 | return dataset; 53 | } 54 | 55 | const size_t unlim = DataSpace::UNLIMITED; 56 | std::vector unlim_shape(idx.size(), unlim); 57 | std::vector chunks(idx.size(), 10); 58 | if (options.isChunked()) { 59 | chunks = options.getChunkSize(); 60 | if (chunks.size() != idx.size()) { 61 | throw error(file, path, "H5Easy::dump: Incorrect dimension ChunkSize"); 62 | } 63 | } 64 | std::vector shape(idx.size()); 65 | for (size_t i = 0; i < idx.size(); ++i) { 66 | shape[i] = idx[i] + 1; 67 | } 68 | DataSpace dataspace = DataSpace(shape, unlim_shape); 69 | DataSetCreateProps props; 70 | props.add(Chunking(chunks)); 71 | DataSet dataset = file.createDataSet(path, dataspace, AtomicType(), props, {}, true); 72 | dataset.select(idx, ones).write(data); 73 | if (options.flush()) { 74 | file.flush(); 75 | } 76 | return dataset; 77 | } 78 | 79 | inline static T load_part(const File& file, 80 | const std::string& path, 81 | const std::vector& idx) { 82 | std::vector ones(idx.size(), 1); 83 | return file.getDataSet(path).select(idx, ones).read(); 84 | } 85 | }; 86 | 87 | } // namespace detail 88 | } // namespace H5Easy 89 | -------------------------------------------------------------------------------- /include/highfive/h5easy_bits/default_io_impl.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #pragma once 10 | 11 | #include "../H5Easy.hpp" 12 | #include "H5Easy_misc.hpp" 13 | #include "H5Easy_scalar.hpp" 14 | 15 | namespace H5Easy { 16 | namespace detail { 17 | 18 | using HighFive::details::inspector; 19 | 20 | template 21 | struct default_io_impl { 22 | inline static std::vector shape(const T& data) { 23 | return inspector::getDimensions(data); 24 | } 25 | 26 | inline static DataSet dump(File& file, 27 | const std::string& path, 28 | const T& data, 29 | const DumpOptions& options) { 30 | using value_type = typename inspector::base_type; 31 | DataSet dataset = initDataset(file, path, shape(data), options); 32 | dataset.write(data); 33 | if (options.flush()) { 34 | file.flush(); 35 | } 36 | return dataset; 37 | } 38 | 39 | inline static T load(const File& file, const std::string& path) { 40 | return file.getDataSet(path).read(); 41 | } 42 | 43 | inline static Attribute dumpAttribute(File& file, 44 | const std::string& path, 45 | const std::string& key, 46 | const T& data, 47 | const DumpOptions& options) { 48 | using value_type = typename inspector::base_type; 49 | Attribute attribute = initAttribute(file, path, key, shape(data), options); 50 | attribute.write(data); 51 | if (options.flush()) { 52 | file.flush(); 53 | } 54 | return attribute; 55 | } 56 | 57 | inline static T loadAttribute(const File& file, 58 | const std::string& path, 59 | const std::string& key) { 60 | auto read_attribute = [&key](const auto& obj) { 61 | return obj.getAttribute(key).template read(); 62 | }; 63 | 64 | return apply_attr_func(file, path, read_attribute); 65 | } 66 | }; 67 | 68 | } // namespace detail 69 | } // namespace H5Easy 70 | -------------------------------------------------------------------------------- /include/highfive/half_float.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace HighFive { 6 | using float16_t = half_float::half; 7 | 8 | template <> 9 | inline AtomicType::AtomicType() { 10 | _hid = detail::h5t_copy(H5T_NATIVE_FLOAT); 11 | // Sign position, exponent position, exponent size, mantissa position, mantissa size 12 | detail::h5t_set_fields(_hid, 15, 10, 5, 0, 10); 13 | // Total datatype size (in bytes) 14 | detail::h5t_set_size(_hid, 2); 15 | // Floating point exponent bias 16 | detail::h5t_set_ebias(_hid, 15); 17 | } 18 | 19 | } // namespace HighFive 20 | -------------------------------------------------------------------------------- /include/highfive/highfive.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | -------------------------------------------------------------------------------- /include/highfive/span.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #pragma once 11 | 12 | #include "bits/H5Inspector_decl.hpp" 13 | #include "bits/inspector_stl_span_misc.hpp" 14 | 15 | #include 16 | 17 | namespace HighFive { 18 | namespace details { 19 | 20 | template 21 | struct inspector>: public inspector_stl_span> { 22 | private: 23 | using super = inspector_stl_span>; 24 | 25 | public: 26 | using type = typename super::type; 27 | using value_type = typename super::value_type; 28 | using base_type = typename super::base_type; 29 | using hdf5_type = typename super::hdf5_type; 30 | }; 31 | 32 | } // namespace details 33 | } // namespace HighFive 34 | -------------------------------------------------------------------------------- /src/benchmarks/Makefile: -------------------------------------------------------------------------------- 1 | # This is minimal makefile to build the benchmark programs 2 | # It was kept as an independent Makefile so that use can trivially change flags 3 | # 4 | # Blue Brain Project - EPFL, 2022 5 | 6 | PROGRAMS:=hdf5_bench hdf5_bench_improved highfive_bench 7 | 8 | CXX?=g++ 9 | COMPILE_OPTS=-g -O2 -Wall 10 | CXXFLAGS=-I ../../include/ `pkg-config --libs --cflags hdf5` -std=c++11 ${COMPILE_OPTS} 11 | 12 | 13 | all: $(PROGRAMS) 14 | 15 | %: %.cpp $(DEPS) 16 | $(CXX) -o $@ $< $(CXXFLAGS) 17 | 18 | clean: 19 | rm -f ${PROGRAMS} 20 | 21 | .PHONY: clean 22 | -------------------------------------------------------------------------------- /src/benchmarks/README.md: -------------------------------------------------------------------------------- 1 | # Benchmarking 2 | 3 | This folder contains several baseline programs used to benchmark HighFive and assess 4 | its overhead wrt no-highfive programs. 5 | 6 | It features a straightforward Makefile whose flags can be easily tuned. By default 7 | compilation features -O2 -g and finds HDF5 via `pkg-config`. 8 | Additionally, a `run_benchmarks.sh` script is provided to measure execution time and 9 | profile using hpctoolkit. 10 | 11 | ## Compile 12 | 13 | Basically, run `make`. By default it compiles with `-g -O2` but it's configurable. e.g. 14 | 15 | ``` 16 | make CXX=clang++ COMPILE_OPTS="-g -O1" 17 | ``` 18 | -------------------------------------------------------------------------------- /src/benchmarks/hdf5_bench.cpp: -------------------------------------------------------------------------------- 1 | #include "hdf5.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define NROWS 1000000 // 1M 7 | #define ROW_LENGTH 10 8 | 9 | const std::vector> data(NROWS, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 10 | 11 | int do_iteration() { 12 | /* Create a new file using default properties. */ 13 | hid_t file_id = H5Fcreate("dataset_integer_raw.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); 14 | 15 | /* Create the data space for the dataset. */ 16 | hsize_t dims[] = {NROWS, ROW_LENGTH}; 17 | hid_t dataspace_id = H5Screate_simple(2, dims, NULL); 18 | 19 | // Row memspace 20 | hsize_t mem_dims[] = {1, ROW_LENGTH}; 21 | hid_t memspace_id = H5Screate_simple(2, mem_dims, NULL); 22 | 23 | /* Create the dataset. */ 24 | hid_t dataset_id = H5Dcreate2( 25 | file_id, "/dataset", H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 26 | 27 | herr_t status; 28 | 29 | /* Write each row to the dataset. */ 30 | for (size_t i = 0; i < NROWS; i++) { 31 | // File Hyperslabs 32 | hsize_t count[] = {1, 10}; 33 | hsize_t offset[] = {i, 0}; 34 | status = H5Sselect_hyperslab(dataspace_id, H5S_SELECT_SET, offset, NULL, count, NULL); 35 | if (status != 0) { 36 | throw(std::runtime_error("H5Sselect_hyperslab failed")); 37 | } 38 | status = H5Dwrite( 39 | dataset_id, H5T_NATIVE_INT, memspace_id, dataspace_id, H5P_DEFAULT, data[i].data()); 40 | if (status != 0) { 41 | throw(std::runtime_error("H5Dwrite failed")); 42 | } 43 | } 44 | 45 | status = H5Sclose(memspace_id); 46 | status |= H5Sclose(dataspace_id); 47 | status |= H5Dclose(dataset_id); 48 | status |= H5Fclose(file_id); 49 | if (status != 0) { 50 | std::cerr << "Error while releasing resources" << std::endl; 51 | } 52 | return status; 53 | } 54 | 55 | int main() { 56 | for (int i = 0; i < 200; i++) { 57 | do_iteration(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/benchmarks/hdf5_bench_improved.cpp: -------------------------------------------------------------------------------- 1 | #include "hdf5.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define NROWS 1000000 // 1M 8 | #define ROW_LENGTH 10 9 | 10 | const std::vector> data(NROWS, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 11 | 12 | inline void check_dimensions(size_t size_vec, size_t size_dataset, size_t dimension) { 13 | if (size_vec != size_dataset) { 14 | std::ostringstream ss; 15 | ss << "Mismatch between vector size (" << size_vec << ") and dataset size (" 16 | << size_dataset; 17 | ss << ") on dimension " << dimension; 18 | throw ss.str(); 19 | } 20 | } 21 | 22 | int do_iteration() { 23 | /* Create a new file using default properties. */ 24 | hid_t file_id = 25 | H5Fcreate("dataset_integer_raw_improved.h5", H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); 26 | 27 | /* Create the data space for the dataset. */ 28 | hsize_t dims[] = {NROWS, ROW_LENGTH}; 29 | hid_t dataspace_id = H5Screate_simple(2, dims, NULL); 30 | 31 | /* Create the dataset. */ 32 | hid_t dataset_id = H5Dcreate2( 33 | file_id, "/dataset", H5T_NATIVE_INT, dataspace_id, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); 34 | 35 | herr_t status; 36 | 37 | /* It's faster to aggregate all rows in a single contiguous buffer to do less IO ops 38 | */ 39 | std::vector data_contig; 40 | data_contig.reserve(NROWS * ROW_LENGTH); 41 | for (const auto& row: data) { 42 | check_dimensions(row.size(), dims[1], 1); 43 | data_contig.insert(data_contig.end(), row.begin(), row.end()); 44 | } 45 | 46 | status = 47 | H5Dwrite(dataset_id, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, data_contig.data()); 48 | 49 | status |= H5Sclose(dataspace_id); 50 | status |= H5Dclose(dataset_id); 51 | status |= H5Fclose(file_id); 52 | if (status != 0) { 53 | std::cerr << "Error while releasing resources" << std::endl; 54 | } 55 | return status; 56 | } 57 | 58 | int main() { 59 | for (int i = 0; i < 200; i++) { 60 | do_iteration(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/benchmarks/highfive_bench.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const std::vector> data(1000000, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); 5 | 6 | int do_iteration() { 7 | HighFive::File("dataset_integer.h5", HighFive::File::Truncate).createDataSet("dataset", data); 8 | return 0; 9 | } 10 | 11 | int main() { 12 | for (int i = 0; i < 200; i++) { 13 | do_iteration(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/benchmarks/imgs/bench_hdf5_base.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfive-devs/highfive/251828e3a17be255d64c362aa9758384d1e8d44a/src/benchmarks/imgs/bench_hdf5_base.png -------------------------------------------------------------------------------- /src/benchmarks/imgs/bench_hdf5_improved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfive-devs/highfive/251828e3a17be255d64c362aa9758384d1e8d44a/src/benchmarks/imgs/bench_hdf5_improved.png -------------------------------------------------------------------------------- /src/benchmarks/imgs/bench_highfive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/highfive-devs/highfive/251828e3a17be255d64c362aa9758384d1e8d44a/src/benchmarks/imgs/bench_highfive.png -------------------------------------------------------------------------------- /src/benchmarks/run_benchmark.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -eu 3 | 4 | executables="hdf5_bench hdf5_bench_improved highfive_bench" 5 | 6 | # Compile all 7 | make 8 | 9 | # Time it : overview and eventual cache warm up 10 | for exe in $executables; do 11 | echo -e "\nRunning $exe" 12 | time ./$exe 13 | done 14 | 15 | if [ $# -eq 0 ]; then 16 | echo "Not running hpctoolkit. Please provide a CLI argument to proceed" 17 | exit 0 18 | fi 19 | 20 | # Profile using hpctoolkit 21 | module load hpctoolkit 22 | rm -rf hpctoolkit-* *.hpcstruct 23 | 24 | for exe in $executables; do 25 | echo -e "\nProfiling $exe" 26 | hpcrun -c f1000000 -e PERF_COUNT_HW_CPU_CYCLES -e REALTIME ./$exe 27 | hpcstruct ./$exe 28 | hpcprof -S $exe.hpcstruct -I ./ -I '../../include/*' hpctoolkit-$exe-* 29 | done 30 | -------------------------------------------------------------------------------- /src/examples/boost_multi_array_2D.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace HighFive; 16 | 17 | // Create a 2D dataset 10x3 of double with boost multi array 18 | // and write it to a file. 19 | int main(void) { 20 | const int nx = 10; 21 | const int ny = 3; 22 | 23 | boost::multi_array array(boost::extents[nx][ny]); 24 | 25 | for (int i = 0; i < nx; ++i) { 26 | for (int j = 0; j < ny; ++j) { 27 | array[i][j] = double(j + i * ny); 28 | } 29 | } 30 | 31 | // We create a new HDF5 file 32 | File file("boost_multiarray_example.h5", File::Truncate); 33 | 34 | // let's create our dataset of the size of the boost::multi_array 35 | file.createDataSet("dset", array); 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /src/examples/boost_multiarray_complex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2020 Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | typedef std::complex complex_t; 17 | 18 | int main() { 19 | boost::multi_array multi_array(boost::extents[3][2][1][1]); 20 | std::fill_n(multi_array.origin(), multi_array.num_elements(), 1.0); 21 | multi_array[1][1][0][0] = complex_t{1.1, 1.2}; 22 | 23 | HighFive::File file("multi_array_complex.h5", HighFive::File::Truncate); 24 | HighFive::DataSet dataset = file.createDataSet("multi_array", multi_array); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/examples/boost_ublas_double.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | // In some versions of Boost (starting with 1.64), you have to include the serialization header 16 | // before ublas 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | using namespace HighFive; 23 | 24 | const std::string FILE_NAME("boost_ublas_double.h5"); 25 | const std::string DATASET_NAME("dset"); 26 | 27 | const size_t size_x = 10; 28 | const size_t size_y = 10; 29 | 30 | int main(void) { 31 | try { 32 | typedef typename boost::numeric::ublas::matrix Matrix; 33 | 34 | // create a 10x10 matrix 35 | Matrix mat(size_x, size_y); 36 | 37 | // fill it 38 | for (std::size_t i = 0; i < size_x; ++i) { 39 | mat(i, i) = static_cast(i); 40 | } 41 | 42 | // Create a new HDF5 file 43 | File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); 44 | 45 | // create a new dataset with the 10x10 Matrix dimension 46 | DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(mat)); 47 | 48 | // write it 49 | dataset.write(mat); 50 | 51 | // now, let read it back 52 | Matrix result; 53 | dataset.read(result); 54 | 55 | // print what we read 56 | std::cout << "Matrix result:\n" << result << std::endl; 57 | 58 | } catch (Exception& err) { 59 | // catch and print any HDF5 error 60 | std::cerr << err.what() << std::endl; 61 | } 62 | 63 | return 0; // successfully terminated 64 | } 65 | -------------------------------------------------------------------------------- /src/examples/broadcasting_arrays.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // This example explains how to read a dataset with some shape into an array of 4 | // some other shape. Naturally, this only makes sense if the number of elements 5 | // doesn't change. 6 | // 7 | // Note that due to how HDF5 works, writing from one shape into some other 8 | // shape is expected to work automatically. 9 | // 10 | // Same is true for reading. However, HighFive also allocates memory, the array 11 | // into which the data is read is forced to have the same shape as the 12 | // memspace. When performing selections it can often happen that one selects a 13 | // one-dimensional slice from a higher dimensional array. In this case we want 14 | // to be able to read into a one dimensional array, e.g. `std::vector`. 15 | // 16 | // Broadcasting is a common technique for hiding benign differences in 17 | // dimensionality. In HighFive we suggest to either "squeeze" or "reshape" the 18 | // memspace, rather than broadcasting. This example demonstrates the required 19 | // syntax. 20 | // 21 | // Note: These techniques can also be used for general hyperslabs which the 22 | // user knows are in fact hypercubes, i.e. regular. 23 | // 24 | // Note: HighFive v2 has support for broadcasting; but because it's quirky, 25 | // less powerful than the demonstrated technique, relied on a compile-time 26 | // constant rank and is quite complex to maintain, the functionality was 27 | // removed from v3. 28 | 29 | using namespace HighFive; 30 | 31 | int main(void) { 32 | File file("broadcasting_arrays.h5", File::Truncate); 33 | 34 | std::vector dims{3, 1}; 35 | std::vector values{1.0, 2.0, 3.0}; 36 | 37 | auto dset = file.createDataSet("dset", DataSpace(dims), create_datatype()); 38 | 39 | // Note that because `values` is one-dimensional, we can't write it 40 | // to a dataset of dimensions `[3, 1]` directly. Instead we use: 41 | dset.squeezeMemSpace({1}).write(values); 42 | 43 | // When reading, (re-)allocation might occur. The shape to be allocated is 44 | // the dimensions of the memspace. Therefore, one might want to either remove 45 | // an axis: 46 | dset.squeezeMemSpace({1}).read(values); 47 | 48 | // or reshape the memspace: 49 | dset.reshapeMemSpace({3}).read(values); 50 | } 51 | -------------------------------------------------------------------------------- /src/examples/compound_types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2021, Blue Brain Project, EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | // Compound datatype test :: May 2021 11 | // ////////////////////////////////// 12 | 13 | #include 14 | 15 | 16 | typedef struct { 17 | double width; 18 | double height; 19 | } Size2D; 20 | 21 | 22 | HighFive::CompoundType create_compound_Size2D() { 23 | return {{"width", HighFive::create_datatype()}, 24 | {"height", HighFive::create_datatype()}}; 25 | } 26 | 27 | HIGHFIVE_REGISTER_TYPE(Size2D, create_compound_Size2D) 28 | 29 | int main() { 30 | const std::string dataset_name("dims"); 31 | 32 | HighFive::File file("compounds_test.h5", HighFive::File::Truncate); 33 | 34 | auto t1 = create_compound_Size2D(); 35 | t1.commit(file, "Size2D"); 36 | 37 | std::vector dims = {{1., 2.5}, {3., 4.5}}; 38 | auto dataset = file.createDataSet(dataset_name, dims); 39 | 40 | auto g1 = file.createGroup("group1"); 41 | g1.createAttribute(dataset_name, dims); 42 | } 43 | -------------------------------------------------------------------------------- /src/examples/create_attribute_string_integer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace HighFive; 16 | 17 | // create a dataset from a vector of string 18 | // read it back and print it 19 | int main(void) { 20 | // Create a new file using the default property lists. 21 | File file("create_attribute.h5", File::Truncate); 22 | 23 | // Create a dummy dataset of one single integer 24 | DataSet dataset = file.createDataSet("dset", DataSpace(1), create_datatype()); 25 | 26 | // Now let's add a attribute on this dataset 27 | // This attribute will be named "note" 28 | // and have the following content 29 | std::string note = "Very important Dataset!"; 30 | 31 | // Write in one line of code: 32 | dataset.createAttribute("note", note); 33 | 34 | // We also add a "version" attribute 35 | // that will be an array 1x2 of integer 36 | std::vector version{1, 0}; 37 | 38 | Attribute v = dataset.createAttribute("version", version); 39 | 40 | // We can also create attributes on the file: 41 | file.createAttribute("file_version", 1); 42 | 43 | // and on groups in the file: 44 | auto group = file.createGroup("group"); 45 | group.createAttribute("secret", 123); 46 | 47 | // let's now list the keys of all attributes 48 | std::vector all_attributes_keys = dataset.listAttributeNames(); 49 | for (const auto& attr: all_attributes_keys) { 50 | std::cout << "attribute: " << attr << std::endl; 51 | } 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /src/examples/create_dataset_double.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // Create a dataset name "dset" of double 4x6 16 | int main(void) { 17 | using namespace HighFive; 18 | 19 | // Create a new file using the default property lists. Note that 20 | // `File::Truncate` will, if present, truncate the file before opening 21 | // it for reading and writing. 22 | File file("create_dataset_example.h5", File::Truncate); 23 | 24 | // Define the size of our dataset: 2x6 25 | std::vector dims{2, 6}; 26 | 27 | // Create the dataset 28 | DataSet dataset = file.createDataSet("dset", DataSpace(dims)); 29 | 30 | double data[2][6] = {{1.1, 2.2, 3.3, 4.4, 5.5, 6.6}, 31 | {11.11, 12.12, 13.13, 14.14, 15.15, 16.16}}; 32 | 33 | // write it 34 | dataset.write(data); 35 | 36 | 37 | return 0; // successfully terminated 38 | } 39 | -------------------------------------------------------------------------------- /src/examples/create_dataset_half_float.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2022, Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | const std::string FILE_NAME("create_dataset_half_float_example.h5"); 18 | const std::string DATASET_NAME("dset"); 19 | 20 | // Create a dataset name "dset", size 4x6, and type float16_t (i.e., 16-bit half-precision 21 | // floating-point format) 22 | // 23 | int main(void) { 24 | using namespace HighFive; 25 | 26 | // Create a new file using the default property lists. 27 | File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); 28 | 29 | // Define the size of our dataset: 4x6 30 | std::vector dims{4, 6}; 31 | 32 | // Create the dataset 33 | DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(dims)); 34 | 35 | std::vector> data; 36 | for (size_t i = 0; i < 4; ++i) { 37 | data.emplace_back(); 38 | for (size_t j = 0; j < 6; ++j) 39 | data[i].emplace_back((i + 1) * (j + 1)); 40 | } 41 | 42 | // write it 43 | dataset.write(data); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/examples/create_datatype.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | using namespace HighFive; 6 | 7 | static const std::string FILE_NAME("create_datatype_example.h5"); 8 | static const std::string DATASET_NAME("test_dataset"); 9 | 10 | 11 | // Struct representation of custom type (type v below) 12 | typedef struct { 13 | char a; 14 | short b; 15 | unsigned long long c; 16 | } csl; 17 | 18 | bool operator==(csl x, csl y) { 19 | return x.a == y.a && x.b == y.b && x.c == y.c; 20 | } 21 | 22 | bool operator!=(csl x, csl y) { 23 | return !(x == y); 24 | } 25 | 26 | // Tell HighFive how to create the HDF5 datatype for this base type by 27 | // using the HIGHFIVE_REGISTER_TYPE macro 28 | CompoundType create_compound_csl() { 29 | return {{"u1", create_datatype()}, 30 | {"u2", create_datatype()}, 31 | {"u3", create_datatype()}}; 32 | } 33 | HIGHFIVE_REGISTER_TYPE(csl, create_compound_csl) 34 | 35 | int main(void) { 36 | File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); 37 | 38 | // Create a simple compound type with automatic alignment of the 39 | // members. For this the type alignment is trivial. 40 | std::vector t_members( 41 | {{"real", create_datatype()}, {"imag", create_datatype()}}); 42 | CompoundType t(t_members); 43 | t.commit(file, "new_type1"); 44 | 45 | // Create a complex nested datatype with manual alignment 46 | CompoundType u({{"u1", t, 0}, {"u2", t, 9}, {"u3", create_datatype(), 20}}, 26); 47 | u.commit(file, "new_type3"); 48 | 49 | // Create a more complex type with automatic alignment. For this the 50 | // type alignment is more complex. 51 | CompoundType v_aligned{{"u1", create_datatype()}, 52 | {"u2", create_datatype()}, 53 | {"u3", create_datatype()}}; 54 | // introspect the compound type 55 | std::cout << "v_aligned size: " << v_aligned.getSize(); 56 | for (const auto& member: v_aligned.getMembers()) { 57 | std::cout << " field " << member.name << " offset: " << member.offset << std::endl; 58 | } 59 | 60 | v_aligned.commit(file, "new_type2_aligned"); 61 | 62 | // Create a more complex type with a fully packed alignment. The 63 | // equivalent type is created with a standard struct alignment in the 64 | // implementation of HighFive::create_datatype above 65 | CompoundType v_packed({{"u1", create_datatype(), 0}, 66 | {"u2", create_datatype(), 1}, 67 | {"u3", create_datatype(), 3}}, 68 | 11); 69 | v_packed.commit(file, "new_type2_packed"); 70 | 71 | 72 | // Initialise some data 73 | std::vector data; 74 | data.push_back({'f', 1, 4}); 75 | data.push_back({'g', -4, 18}); 76 | 77 | // Write the data into the file in a fully packed form 78 | DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(2), v_packed); 79 | dataset.write(data); 80 | 81 | file.flush(); 82 | 83 | // Read a subset of the data back 84 | std::vector result; 85 | dataset.select({0}, {2}).read(result); 86 | 87 | for (size_t i = 0; i < data.size(); ++i) { 88 | if (result[i] != data[i]) { 89 | std::cout << "result[" << i << "]:" << std::endl; 90 | std::cout << " " << result[i].a << std::endl; 91 | std::cout << " " << result[i].b << std::endl; 92 | std::cout << " " << result[i].c << std::endl; 93 | std::cout << "data[" << i << "]:" << std::endl; 94 | std::cout << " " << data[i].a << std::endl; 95 | std::cout << " " << data[i].b << std::endl; 96 | std::cout << " " << data[i].c << std::endl; 97 | } 98 | } 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /src/examples/create_extensible_dataset.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | const std::string FILE_NAME("create_extensible_dataset_example.h5"); 16 | const std::string DATASET_NAME("dset"); 17 | 18 | // Create a dataset name "dset" of double 4x6 19 | // 20 | int main(void) { 21 | using namespace HighFive; 22 | 23 | // Create a new file using the default property lists. 24 | File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); 25 | 26 | // Create a dataspace with initial shape and max shape 27 | DataSpace dataspace = DataSpace({4, 5}, {17, DataSpace::UNLIMITED}); 28 | 29 | // Use chunking 30 | DataSetCreateProps props; 31 | props.add(Chunking(std::vector{2, 2})); 32 | 33 | // Create the dataset 34 | DataSet dataset = file.createDataSet(DATASET_NAME, dataspace, create_datatype(), props); 35 | 36 | // Write into the initial part of the dataset 37 | double t1[3][1] = {{2.0}, {2.0}, {4.0}}; 38 | dataset.select({0, 0}, {3, 1}).write(t1); 39 | 40 | // Resize the dataset to a larger size 41 | dataset.resize({4, 6}); 42 | 43 | // Write into the new part of the dataset 44 | double t2[1][3] = {{4.0, 8.0, 6.0}}; 45 | dataset.select({3, 3}, {1, 3}).write(t2); 46 | 47 | // now we read it back 48 | std::vector> result; 49 | dataset.read(result); 50 | 51 | // we print it out and see: 52 | // 2 0 0 0 0 0 53 | // 2 0 0 0 0 0 54 | // 4 0 0 0 0 0 55 | // 0 0 0 4 8 6 56 | for (auto row: result) { 57 | for (auto col: row) 58 | std::cout << " " << col; 59 | std::cout << std::endl; 60 | } 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/examples/create_large_attribute.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | int main() { 7 | std::vector large_attr(16000, 0.0); 8 | 9 | auto fapl = HighFive::FileAccessProps::Default(); 10 | fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); 11 | HighFive::File file("create_large_attribute.h5", HighFive::File::Truncate, fapl); 12 | auto gcpl = HighFive::GroupCreateProps::Default(); 13 | gcpl.add(HighFive::AttributePhaseChange(0, 0)); 14 | 15 | auto group = file.createGroup("grp", gcpl); 16 | group.createAttribute("attr", large_attr); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /src/examples/create_page_allocated_files.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2022, Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | // This example requires HDF5 version 1.10.1 or newer. 18 | #if H5_VERSION_GE(1, 10, 1) 19 | 20 | // This example show how to create an HDF5 file that internally aggregates 21 | // metadata and raw data into separate pages. The advantage of this approach 22 | // is that reading a single page, pulls in the metadata for a large chunk of 23 | // the file. 24 | // 25 | // This can be very useful when dealing with many small datasets. Note, this 26 | // is an optimization. Therefore, you must perform measurements in order to 27 | // know if this should be used. 28 | // 29 | // Internally, it uses two free space managers, one for metadata and one for 30 | // raw data. When space for data is allocated, the corresponding free space 31 | // manager is asked to allocate space. It will look if there is enough space 32 | // on a partially filled paged, if yes it keeps filling the page, if not it 33 | // requests page aligned space from the file driver as needed. Upstream 34 | // documentation explains the details well in: 35 | // 36 | // RFC: HDF5 File Space Management: Paged Aggregation 37 | 38 | int main() { 39 | using namespace HighFive; 40 | 41 | // Create a new file requesting paged allocation. 42 | auto create_props = FileCreateProps{}; 43 | 44 | // Let request pagesizes of 16 kB. This setting should be tuned 45 | // in real applications. We'll allow HDF5 to not keep track of 46 | // left-over free space of size less than 128 bytes. Finally, 47 | // we don't need the free space manager to be stored in the 48 | // HDF5 file. 49 | size_t pagesize = 16 * 1024; // Must be tuned. 50 | size_t threshold = 128; 51 | size_t persist = false; 52 | 53 | create_props.add(FileSpaceStrategy(H5F_FSPACE_STRATEGY_PAGE, persist, threshold)); 54 | create_props.add(FileSpacePageSize(pagesize)); 55 | 56 | File file("create_page_allocated_files.h5", File::Truncate, create_props); 57 | 58 | // The `file` (and also the low-level `file.getId()`) behave as normal, i.e. 59 | // one can proceed to add content to the file as usual. 60 | 61 | auto data = std::vector{0.0, 1.0, 2.0}; 62 | file.createDataSet("data", data); 63 | 64 | return 0; 65 | } 66 | #else 67 | #include 68 | int main() { 69 | std::cout << "This example can't be run prior to HDF5 1.10.1.\n"; 70 | return 0; 71 | } 72 | #endif 73 | -------------------------------------------------------------------------------- /src/examples/easy_attribute.cpp: -------------------------------------------------------------------------------- 1 | /// To enable plug-ins, load the relevant libraries BEFORE HighFive. E.g. 2 | /// 3 | /// #include 4 | /// #include 5 | /// #include 6 | /// 7 | /// or ask HighFive to include them. E.g. 8 | /// 9 | /// #define H5_USE_XTENSOR 10 | /// #define H5_USE_EIGEN 11 | /// #include 12 | /// 13 | 14 | // optionally enable plug-in xtensor 15 | #ifdef H5_USE_XTENSOR 16 | #include "bits/xtensor_header_version.hpp" 17 | #if HIGHFIVE_XTENSOR_HEADER_VERSION == 1 18 | #include 19 | #elif HIGHFIVE_XTENSOR_HEADER_VERSION == 2 20 | #include 21 | #else 22 | #error "Failed to detect HIGHFIVE_XTENSOR_HEADER_VERSION." 23 | #endif 24 | #endif 25 | 26 | // optionally enable plug-in Eigen 27 | #ifdef H5_USE_EIGEN 28 | #include 29 | #endif 30 | 31 | #include 32 | 33 | int main() { 34 | H5Easy::File file("example.h5", H5Easy::File::Overwrite); 35 | 36 | std::vector measurement = {1.0, 2.0, 3.0}; 37 | std::string desc = "This is an important dataset."; 38 | double temperature = 1.234; 39 | 40 | H5Easy::dump(file, "/path/to/measurement", measurement); 41 | H5Easy::dumpAttribute(file, "/path/to/measurement", "description", desc); 42 | H5Easy::dumpAttribute(file, "/path/to/measurement", "temperature", temperature); 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /src/examples/easy_dumpoptions.cpp: -------------------------------------------------------------------------------- 1 | /// To enable plug-ins, load the relevant libraries BEFORE HighFive. E.g. 2 | /// 3 | /// #include 4 | /// #include 5 | /// #include 6 | /// 7 | /// or ask HighFive to include them. E.g. 8 | /// 9 | /// #define H5_USE_XTENSOR 10 | /// #define H5_USE_EIGEN 11 | /// #include 12 | /// 13 | 14 | // optionally enable plug-in xtensor 15 | #ifdef H5_USE_XTENSOR 16 | #include 17 | #if HIGHFIVE_XTENSOR_HEADER_VERSION == 1 18 | #include 19 | #elif HIGHFIVE_XTENSOR_HEADER_VERSION == 2 20 | #include 21 | #else 22 | #error "Failed to detect HIGHFIVE_XTENSOR_HEADER_VERSION." 23 | #endif 24 | #endif 25 | 26 | // optionally enable plug-in Eigen 27 | #ifdef H5_USE_EIGEN 28 | #include 29 | #endif 30 | 31 | #include 32 | 33 | int main() { 34 | H5Easy::File file("example.h5", H5Easy::File::Overwrite); 35 | 36 | // plain options 37 | { 38 | std::vector A = {1.0, 2.0, 3.0}; 39 | 40 | H5Easy::dump(file, "/path/to/A", A); 41 | H5Easy::dump(file, "/path/to/A", A, H5Easy::DumpMode::Overwrite); 42 | } 43 | 44 | // advanced - compression 45 | { 46 | std::vector B = {1.0, 2.0, 3.0}; 47 | 48 | H5Easy::dump(file, "/path/to/B", B, H5Easy::DumpOptions(H5Easy::Compression())); 49 | 50 | H5Easy::dump(file, 51 | "/path/to/B", 52 | B, 53 | H5Easy::DumpOptions(H5Easy::Compression(), H5Easy::DumpMode::Overwrite)); 54 | } 55 | 56 | // advanced - compression - set compression level 57 | { 58 | std::vector C = {1.0, 2.0, 3.0}; 59 | 60 | H5Easy::dump(file, "/path/to/C", C, H5Easy::DumpOptions(H5Easy::Compression(8))); 61 | } 62 | 63 | // advanced - compression - set compression level & chunk size 64 | { 65 | std::vector D = {1.0, 2.0, 3.0}; 66 | 67 | H5Easy::DumpOptions options(H5Easy::Compression(8)); 68 | options.setChunkSize({3}); 69 | 70 | H5Easy::dump(file, "/path/to/D", D, options); 71 | } 72 | 73 | // advanced - set chunk size 74 | { 75 | int E = 10; 76 | 77 | H5Easy::DumpOptions options; 78 | options.setChunkSize({100, 100}); 79 | 80 | H5Easy::dump(file, "/path/to/E", E, {0, 0}, options); 81 | H5Easy::dump(file, "/path/to/E", E, {0, 1}, options); 82 | // ... 83 | } 84 | 85 | // advanced - no automatic flushing 86 | { 87 | std::vector F = {1.0, 2.0, 3.0}; 88 | 89 | H5Easy::dump(file, "/path/to/F", F, H5Easy::DumpOptions(H5Easy::Flush::False)); 90 | 91 | file.flush(); 92 | } 93 | 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /src/examples/easy_load_dump.cpp: -------------------------------------------------------------------------------- 1 | /// To enable plug-ins, load the relevant libraries BEFORE HighFive. E.g. 2 | /// 3 | /// #include 4 | /// #include 5 | /// #include 6 | /// 7 | /// or ask HighFive to include them. E.g. 8 | /// 9 | /// #define H5_USE_XTENSOR 10 | /// #define H5_USE_EIGEN 11 | /// #include 12 | /// 13 | 14 | // optionally enable plug-in xtensor 15 | #ifdef H5_USE_XTENSOR 16 | #include 17 | #if HIGHFIVE_XTENSOR_HEADER_VERSION == 1 18 | #include 19 | #elif HIGHFIVE_XTENSOR_HEADER_VERSION == 2 20 | #include 21 | #else 22 | #error "Failed to detect HIGHFIVE_XTENSOR_HEADER_VERSION." 23 | #endif 24 | #endif 25 | 26 | // optionally enable plug-in Eigen 27 | #ifdef H5_USE_EIGEN 28 | #include 29 | #endif 30 | 31 | #include 32 | 33 | int main() { 34 | H5Easy::File file("example.h5", H5Easy::File::Overwrite); 35 | 36 | // (over)write and read scalar 37 | { 38 | int A = 10; 39 | 40 | H5Easy::dump(file, "/path/to/A", A); 41 | H5Easy::dump(file, "/path/to/A", A, H5Easy::DumpMode::Overwrite); 42 | } 43 | 44 | // (over)write and read std::vector 45 | { 46 | std::vector B = {1., 2., 3.}; 47 | 48 | H5Easy::dump(file, "/path/to/B", B); 49 | H5Easy::dump(file, "/path/to/B", B, H5Easy::DumpMode::Overwrite); 50 | 51 | B = H5Easy::load>(file, "/path/to/B"); 52 | } 53 | 54 | // (over)write scalar in (automatically expanding) extendible DataSet, 55 | // read item from the DataSet 56 | { 57 | int C = 10; 58 | 59 | H5Easy::dump(file, "/path/to/C", C, {0}); 60 | H5Easy::dump(file, "/path/to/C", C, {1}); 61 | H5Easy::dump(file, "/path/to/C", C, {3}); 62 | 63 | C = H5Easy::load(file, "/path/to/C", {0}); 64 | } 65 | 66 | // get the size/shape of a DataSet 67 | { 68 | // outputs "size_t" 69 | H5Easy::getSize(file, "/path/to/C"); 70 | 71 | // outputs "std::vector" 72 | H5Easy::getShape(file, "/path/to/C"); 73 | } 74 | 75 | #ifdef H5_USE_EIGEN 76 | // (over)write and read Eigen::Matrix 77 | { 78 | // matrix 79 | Eigen::MatrixXd D = Eigen::MatrixXd::Random(10, 5); 80 | 81 | H5Easy::dump(file, "/path/to/D", D); 82 | H5Easy::dump(file, "/path/to/D", D, H5Easy::DumpMode::Overwrite); 83 | 84 | D = H5Easy::load(file, "/path/to/D"); 85 | 86 | 87 | Eigen::ArrayXd D2 = Eigen::ArrayXd::Random(30); 88 | 89 | H5Easy::dump(file, "/path/to/D2", D2); 90 | H5Easy::dump(file, "/path/to/D2", D2, H5Easy::DumpMode::Overwrite); 91 | 92 | D2 = H5Easy::load(file, "/path/to/D2"); 93 | } 94 | #endif 95 | 96 | #ifdef H5_USE_XTENSOR 97 | // (over)write and read xt::xtensor (or xt::xarray) 98 | { 99 | xt::xtensor E = xt::arange(10); 100 | 101 | H5Easy::dump(file, "/path/to/E", E); 102 | H5Easy::dump(file, "/path/to/E", E, H5Easy::DumpMode::Overwrite); 103 | 104 | E = H5Easy::load>(file, "/path/to/E"); 105 | } 106 | #endif 107 | 108 | return 0; 109 | } 110 | -------------------------------------------------------------------------------- /src/examples/eigen_map.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Example showing reading and writing of `Eigen::Map`. Using 5 | // `Map` as an example, but `Map` works 6 | // analogously. 7 | // 8 | // Both `Eigen::Matrix` and `Eigen::Vector` have their own examples. 9 | 10 | int main() { 11 | HighFive::File file("eigen_map.h5", HighFive::File::Truncate); 12 | 13 | // Somehow allocate some memory: 14 | double* p1 = (double*) malloc(4 * 3 * sizeof(double)); 15 | 16 | Eigen::Map A(p1, 4, 3); 17 | 18 | // clang-format off 19 | A << 1, 2, 3, 20 | 4, 5, 6, 21 | 7, 8, 9, 22 | 10, 11, 12; 23 | // clang-format on 24 | std::cout << "A = \n" << A << "\n\n"; 25 | 26 | // Write it to the file: 27 | file.createDataSet("mat", A); 28 | 29 | // ... and read it back as fixed-size and row-major: 30 | using Matrix43d = Eigen::Matrix; 31 | 32 | // Again, memory was obtain somehow, and we create an `Eigen::Map` 33 | // from it: 34 | double* p2 = (double*) malloc(4 * 3 * sizeof(double)); 35 | Eigen::Map B(p2, 4, 3); 36 | 37 | // Since, we've pre-allocated the memory, we use the overload of `read` 38 | // accepts `B` and an argument. Note, this will throw if `B` needs to be 39 | // resized, because a map shouldn't resize the underlying memory: 40 | file.getDataSet("mat").read(B); 41 | 42 | std::cout << "B = \n" << B << "\n"; 43 | 44 | free(p1); 45 | free(p2); 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /src/examples/eigen_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Example showing reading and writing of `Eigen::Matrix`. Using 5 | // `Eigen::Matrix` as an example, but `Eigen::Array` works analogously. 6 | // 7 | // Both `Eigen::Vector` and `Eigen::Map` have their own examples. 8 | 9 | int main() { 10 | HighFive::File file("eigen_matrix.h5", HighFive::File::Truncate); 11 | 12 | // Create a matrix. 13 | Eigen::MatrixXd A(4, 3); 14 | // clang-format off 15 | A << 1, 2, 3, 16 | 4, 5, 6, 17 | 7, 8, 9, 18 | 10, 11, 12; 19 | // clang-format on 20 | // 21 | std::cout << "A = \n" << A << "\n\n"; 22 | 23 | // Write it to the file: 24 | file.createDataSet("mat", A); 25 | 26 | // ... and read it back as fixed-size and row-major: 27 | using Matrix43d = Eigen::Matrix; 28 | auto B = file.getDataSet("mat").read(); 29 | 30 | std::cout << "B = \n" << B << "\n"; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/examples/eigen_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Example showing reading and writing of `Eigen::Matrix`. Using 5 | // `Eigen::Matrix` as an example, but `Eigen::Array` works analogously. 6 | // 7 | // Both `Eigen::Vector` and `Eigen::Map` have their own examples. 8 | 9 | int main() { 10 | HighFive::File file("eigen_vector.h5", HighFive::File::Truncate); 11 | 12 | // Create a matrix. 13 | Eigen::VectorXd v(3); 14 | v << 1, 2, 3; 15 | std::cout << "v = \n" << v << "\n\n"; 16 | 17 | // Write it to the file: 18 | file.createDataSet("col_vec", v); 19 | 20 | // The twist is that Eigen typedefs: 21 | // using VectorXd = Matrix; 22 | // 23 | // Therefore, for HighFive it's indistinguishable from a Nx1 matrix. Since, 24 | // Eigen distinguishes row and column vectors, the HighFive chooses to 25 | // respect the distinction and deduces the shape of vector as Nx1. 26 | 27 | // ... and read it back as fixed-size: 28 | auto w = file.getDataSet("col_vec").read(); 29 | 30 | std::cout << "w = \n" << w << "\n"; 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/examples/hl_hdf5_inmemory_files.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2022, Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | using namespace HighFive; 17 | 18 | class InMemoryFile: public HighFive::File { 19 | public: 20 | explicit InMemoryFile(std::vector buffer) 21 | : _buffer(std::move(buffer)) { 22 | _hid = H5LTopen_file_image(_buffer.data(), 23 | sizeof(_buffer[0]) * _buffer.size(), 24 | H5LT_FILE_IMAGE_DONT_RELEASE | H5LT_FILE_IMAGE_DONT_COPY); 25 | } 26 | 27 | private: 28 | std::vector _buffer; 29 | }; 30 | 31 | 32 | // Create a 2D dataset 10x3 of double with eigen matrix 33 | // and write it to a file 34 | int main(void) { 35 | const std::string file_name("inmemory_file.h5"); 36 | const std::string dataset_name("dset"); 37 | 38 | auto data = std::vector{1.0, 2.0, 3.0}; 39 | 40 | { 41 | // We create an HDF5 file. 42 | File file(file_name, File::Truncate); 43 | file.createDataSet(dataset_name, data); 44 | } 45 | 46 | // Simulate having an inmemory file by reading a file 47 | // byte-by-byte into RAM. 48 | auto buffer = std::vector(1ul << 20); 49 | auto file = std::fopen(file_name.c_str(), "r"); 50 | auto nread = std::fread(buffer.data(), sizeof(buffer[0]), buffer.size(), file); 51 | std::cout << "Bytes read: " << nread << "\n"; 52 | 53 | // Create a file from a buffer. 54 | auto h5 = InMemoryFile(std::move(buffer)); 55 | 56 | // Read a dataset as usual. 57 | auto read_back = h5.getDataSet(dataset_name).read>(); 58 | 59 | // Check if the values match. 60 | for (size_t i = 0; i < read_back.size(); ++i) { 61 | if (read_back[i] != data[i]) { 62 | throw std::runtime_error("Values don't match."); 63 | } else { 64 | std::cout << "read_back[" << i << "] = " << read_back[i] << "\n"; 65 | } 66 | } 67 | 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /src/examples/parallel_hdf5_independent_io.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * Copyright (c), 2022, Blue Brain Project 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. 6 | * (See accompanying file LICENSE_1_0.txt or copy at 7 | * http://www.boost.org/LICENSE_1_0.txt) 8 | * 9 | */ 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | const std::string file_name("parallel_independent_example.h5"); 19 | 20 | // This is an example of how to let MPI ranks read independent parts of the 21 | // HDF5 file. 22 | int main(int argc, char** argv) { 23 | int mpi_rank, mpi_size; 24 | 25 | // initialize MPI 26 | MPI_Init(&argc, &argv); 27 | MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); 28 | MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); 29 | 30 | using namespace HighFive; 31 | try { 32 | // We perform a preprocessing step, to create a file: 33 | // { 34 | // "g0": { "x": [ 0.0, 0.0, 0.0 ] } 35 | // "g1": { "x": [ 1.0, 2.0, 3.0 ] } 36 | // "g2": { "x": [ 2.0, 4.0, 6.0 ] } 37 | // ... 38 | // } 39 | if (mpi_rank == 0) { 40 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 41 | 42 | for (int i = 0; i < mpi_size; ++i) { 43 | std::stringstream group_name; 44 | group_name << "g" << i; 45 | 46 | // Create a group: `f"g{mpi_rank}"` 47 | auto group = file.createGroup(group_name.str()); 48 | 49 | std::vector x{double(i), 2 * double(i), 3 * double(i)}; 50 | group.createDataSet("x", x); 51 | } 52 | } 53 | 54 | // We need to wait for the file to be created, before proceeding with the 55 | // actual example. 56 | MPI_Barrier(MPI_COMM_WORLD); 57 | 58 | // The example can start! 59 | // 60 | // Let's inform HDF5 that we want MPI-IO. We need a file access property 61 | // list, and request MPI-IO file access. 62 | FileAccessProps fapl; 63 | fapl.add(MPIOFileAccess{MPI_COMM_WORLD, MPI_INFO_NULL}); 64 | 65 | // Do not ask for collective metadata I/O reads. You can consider 66 | // asking for collective metadata writes, (since they must be collective 67 | // anyway, otherwise MPI ranks might have differing view of how the same 68 | // HDF5 is internally structured). But here we only read. 69 | // 70 | // fapl.add(MPIOCollectiveMetadataWrite{}); 71 | 72 | // Now we can create the file as usual. 73 | File file(file_name, File::ReadOnly, fapl); 74 | 75 | // Note that this operation isn't collective. Each MPI rank is requesting to 76 | // open a different group. 77 | std::stringstream dataset_name; 78 | dataset_name << "g" << mpi_rank << "/x"; 79 | 80 | // Again this isn't collective since, different MPI ranks are reading 81 | // from different datasets. 82 | auto x = file.getDataSet(dataset_name.str()).read>(); 83 | 84 | // Let's create some more obviously independent accesses, and explicitely 85 | // open the intermediate group: 86 | if (mpi_rank % 2 == 0) { 87 | std::stringstream other_group_name; 88 | other_group_name << "g" << (mpi_rank + 1) % mpi_size; 89 | auto other_group = file.getGroup(other_group_name.str()); 90 | 91 | auto y = other_group.getDataSet("x").read>(); 92 | } 93 | } catch (Exception& err) { 94 | // catch and print any HDF5 error 95 | std::cerr << err.what() << std::endl; 96 | MPI_Abort(MPI_COMM_WORLD, 1); 97 | } 98 | 99 | MPI_Finalize(); 100 | return 0; // successfully terminated 101 | } 102 | -------------------------------------------------------------------------------- /src/examples/read_write_dataset_string.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace HighFive; 16 | 17 | const std::string file_name("create_dataset_string_example.h5"); 18 | const std::string dataset_name("story"); 19 | 20 | // create a dataset from a vector of string 21 | // read it back and print it 22 | int main(void) { 23 | // Create a new file using the default property lists. 24 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 25 | 26 | std::vector string_list; 27 | string_list.push_back("Hello World !"); 28 | string_list.push_back( 29 | "This string list is mapped to a dataset of " 30 | "variable length string"); 31 | string_list.push_back("Encoding is done in UTF-8 - 你好 - Здравствуйте!"); 32 | string_list.push_back("May the force be with you"); 33 | string_list.push_back("Enjoy !"); 34 | 35 | // create a dataset ready to contains strings of the size of the vector 36 | // string_list 37 | DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(string_list)); 38 | 39 | // let's write our vector of string 40 | dataset.write(string_list); 41 | 42 | // now we read it back 43 | std::vector result_string_list; 44 | dataset.read(result_string_list); 45 | 46 | for (size_t i = 0; i < result_string_list.size(); ++i) { 47 | std::cout << ":" << i << " " << result_string_list[i] << "\n"; 48 | } 49 | 50 | return 0; // successfully terminated 51 | } 52 | -------------------------------------------------------------------------------- /src/examples/read_write_raw_ptr.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * Copyright (c), 2022, Blue Brain Project 4 | * 5 | * Distributed under the Boost Software License, Version 1.0. 6 | * (See accompanying file LICENSE_1_0.txt or copy at 7 | * http://www.boost.org/LICENSE_1_0.txt) 8 | * 9 | */ 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | const std::string file_name("read_write_raw_ptr.h5"); 17 | const std::string dataset_name("array"); 18 | 19 | // This create a "multi-dimensional" array. Meaning a pointer with 20 | // dimensions. The `std::vector` is mearly a convenient way 21 | // of allocating and releasing memory. 22 | // 23 | // Conceptionually this is only a raw pointer with dimensions. The 24 | // data is store in row-major, aka C-style, without stride, offset 25 | // or padding. 26 | std::vector make_array(const std::vector& dims) { 27 | auto n_elements = dims[0] * dims[1]; 28 | std::vector nd_array(n_elements, 0.0); 29 | 30 | for (size_t i = 0; i < dims[0]; ++i) { 31 | for (size_t j = 0; j < dims[1]; ++j) { 32 | nd_array[j + i * dims[1]] = double(j) + 100.0 * double(i); 33 | } 34 | } 35 | 36 | return nd_array; 37 | } 38 | 39 | int main(void) { 40 | using namespace HighFive; 41 | 42 | // Create a new file using the default property lists. 43 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 44 | 45 | // Let's write to file. 46 | { 47 | std::vector dims{3, 5}; 48 | auto nd_array = make_array(dims); 49 | 50 | // First, create a dataset with the correct dimensions. 51 | auto dataset = file.createDataSet(dataset_name, DataSpace(dims)); 52 | 53 | // Then write, using the raw pointer. 54 | dataset.write_raw(nd_array.data()); 55 | } 56 | 57 | // Let's read from file. 58 | { 59 | auto dataset = file.getDataSet(dataset_name); 60 | 61 | // First read the dimensions. 62 | auto dims = dataset.getDimensions(); 63 | 64 | // Then allocate memory. 65 | auto n_elements = dims[0] * dims[1]; 66 | auto nd_array = std::vector(n_elements); 67 | 68 | // Finally, read into the memory by passing a raw pointer to the library. 69 | dataset.read_raw(nd_array.data()); 70 | } 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/examples/read_write_single_scalar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | const std::string file_name("read_write_scalar.h5"); 16 | const std::string dataset_name("single_scalar"); 17 | 18 | // Create a dataset name "single_scalar" 19 | // which contains only the perfect integer number "42" 20 | // 21 | int main(void) { 22 | using namespace HighFive; 23 | 24 | // Create a new file using the default property lists. 25 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 26 | 27 | int perfect_number = 42; 28 | 29 | // Create the dataset 30 | DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(perfect_number)); 31 | 32 | // write it 33 | dataset.write(perfect_number); 34 | 35 | // flush everything 36 | file.flush(); 37 | 38 | // let's read it back 39 | int potentially_perfect_number; 40 | 41 | dataset.read(potentially_perfect_number); 42 | 43 | std::cout << "perfect number: " << potentially_perfect_number << std::endl; 44 | 45 | return 0; // successfully terminated 46 | } 47 | -------------------------------------------------------------------------------- /src/examples/read_write_std_span.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2024, Blue Brain Project 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | // This example demonstrates using `std::span`. An `std::span` is a pointer 11 | // with a size. 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #include 19 | 20 | int main(void) { 21 | using namespace HighFive; 22 | 23 | std::string file_name = "read_write_span.h5"; 24 | std::string dataset_name = "array"; 25 | 26 | File file(file_name, File::Truncate); 27 | 28 | // Let's write to file. 29 | { 30 | // Assume we have one-dimensional data in some unsupported format (we 31 | // use `std::vector` for simplicity). Further, assume that the data is 32 | // stored contiguously. Then one can create an `std::span`. 33 | std::vector values{1.0, 2.0, 3.0}; 34 | auto view = std::span(values.data(), values.size()); 35 | 36 | // Given the span, HighFive can deduce the shape of the dataset. Hence, 37 | // spans are fully supported when writing. For example: 38 | auto dataset = file.createDataSet(dataset_name, view); 39 | } 40 | 41 | // Let's read from file. 42 | { 43 | auto dataset = file.getDataSet(dataset_name); 44 | 45 | // Since spans are views, HighFive can't (or wont) allocate memory. 46 | // Instead one must preallocate memory and then create a span for that 47 | // memory: 48 | auto values = std::vector(dataset.getElementCount()); 49 | auto view = std::span(values.data(), values.size()); 50 | 51 | // ... now we can read into the preallocated memory: 52 | dataset.read(view); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /src/examples/read_write_vector_dataset.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | using namespace HighFive; 16 | 17 | const std::string file_name("dataset_integer.h5"); 18 | const std::string dataset_name("dset"); 19 | const size_t size_dataset = 20; 20 | 21 | // create a dataset 1D from a vector of string 22 | void write_dataset() { 23 | // we create a new hdf5 file 24 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 25 | 26 | std::vector data(size_dataset); 27 | for (size_t i = 0; i < data.size(); ++i) { 28 | data[i] = int(i); 29 | } 30 | 31 | // let's create a dataset of native integer with the size of the vector 32 | // 'data' 33 | DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(data)); 34 | 35 | // let's write our vector of int to the HDF5 dataset 36 | dataset.write(data); 37 | } 38 | 39 | // read our data back 40 | void read_dataset() { 41 | // we open the existing hdf5 file we created before 42 | File file(file_name, File::ReadOnly); 43 | 44 | std::vector read_data; 45 | 46 | // we get the dataset 47 | DataSet dataset = file.getDataSet(dataset_name); 48 | 49 | // we convert the hdf5 dataset to a single dimension vector 50 | dataset.read(read_data); 51 | 52 | for (size_t i = 0; i < read_data.size(); ++i) { 53 | std::cout << read_data[i] << " "; 54 | } 55 | std::cout << "\n"; 56 | } 57 | 58 | int main(void) { 59 | write_dataset(); 60 | read_dataset(); 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /src/examples/read_write_vector_dataset_references.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2021 Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // create a dataset 1D from a vector of int 16 | void write_dataset() { 17 | // we create a new hdf5 file 18 | HighFive::File file("dataset_integer.h5", HighFive::File::Overwrite); 19 | 20 | // we create a new group 21 | HighFive::Group group = file.createGroup("a_group"); 22 | 23 | std::vector data(20); 24 | std::iota(data.begin(), data.end(), 0); 25 | 26 | // let's create a dataset of native integer with the size of the vector 27 | // 'data' inside the group 28 | auto dataset = group.createDataSet("source_dataset", data); 29 | 30 | // create a reference to the dataset containing the integers 31 | HighFive::Reference ref = HighFive::Reference(group, dataset); 32 | std::vector ref_container{ref}; 33 | 34 | // in similar fashion, we store as dataset the vector of reference that we want 35 | HighFive::DataSet ref_set = group.createDataSet("reference_dataset", ref_container); 36 | } 37 | 38 | // read our data back 39 | void read_dataset() { 40 | // we open the existing hdf5 file we created before 41 | HighFive::File file("dataset_integer.h5", HighFive::File::ReadOnly); 42 | 43 | // we load the group 44 | HighFive::Group my_group = file.getGroup("a_group"); 45 | 46 | // we load the dataset that contains the reference 47 | HighFive::DataSet ref_dataset = my_group.getDataSet("reference_dataset"); 48 | 49 | // we load the vector of references 50 | std::vector expected_references; 51 | ref_dataset.read(expected_references); 52 | 53 | // we use the stored reference and dereference it to gain access in the integers' 54 | // dataset 55 | HighFive::DataSet expected_dataset = expected_references[0].dereference( 56 | my_group); 57 | 58 | // as usual, we load the vector with numbers from the extracted dataset 59 | std::vector read_data; 60 | expected_dataset.read(read_data); 61 | 62 | // and voila, the payload we excepted 63 | for (int i: read_data) { 64 | std::cout << i << " "; 65 | } 66 | } 67 | 68 | int main() { 69 | write_dataset(); 70 | read_dataset(); 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /src/examples/readme_snippet.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace HighFive; 4 | 5 | int main() { 6 | std::string filename = "/tmp/new_file.h5"; 7 | 8 | { 9 | // We create an empty HDF55 file, by truncating an existing 10 | // file if required: 11 | File file(filename, File::Truncate); 12 | 13 | std::vector data(50, 1); 14 | file.createDataSet("grp/data", data); 15 | } 16 | 17 | { 18 | // We open the file as read-only: 19 | File file(filename, File::ReadOnly); 20 | auto dataset = file.getDataSet("grp/data"); 21 | 22 | // Read back, with allocating: 23 | auto data = dataset.read>(); 24 | 25 | // Because `pre_allocated` has the correct size, this will 26 | // not cause `pre_allocated` to be reallocated: 27 | auto pre_allocated = std::vector(50); 28 | dataset.read(pre_allocated); 29 | } 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /src/examples/renaming_objects.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace HighFive; 4 | 5 | int main(void) { 6 | /* We are going to create group in root directory then add 7 | * dataset to this group and attach attribute to the dataset. 8 | * Then we are trying to get path to the root, group dataset 9 | * and the name of the dataset. 10 | * Secondly we will move dataset with attached attribute to 11 | * some destination path. 12 | * To check if dataset object is still valid, we create a 13 | * second attribute */ 14 | 15 | // Create a new file using the default property lists. 16 | File file("names.h5", File::ReadWrite | File::Create | File::Truncate); 17 | 18 | // Create a group 19 | Group group = file.createGroup("group"); 20 | 21 | // Create a dummy dataset of one single integer 22 | DataSet dataset = group.createDataSet("data", DataSpace(1), create_datatype()); 23 | dataset.write(100); 24 | 25 | // Let's also add a attribute to this dataset 26 | std::string string_list("very important DataSet!"); 27 | Attribute attribute = dataset.createAttribute("attribute", 28 | DataSpace::From(string_list)); 29 | attribute.write(string_list); 30 | 31 | // Get path and names 32 | std::cout << "root path: " << file.getPath() << std::endl; 33 | std::cout << "group path: " << group.getPath() << std::endl; 34 | std::cout << "dataset path: " << dataset.getPath() << std::endl; 35 | std::cout << "attribute name: " << attribute.getName() << std::endl; 36 | std::cout << std::endl; 37 | 38 | // Move dataset with its attribute to another destination path 39 | file.rename("/group/data", "/NewGroup/SubGroup/movedData"); 40 | 41 | // As you can see to reach destination path new groups were created as well 42 | std::cout << "dataset new path: " << dataset.getPath() << std::endl; 43 | 44 | // We can still use moved dataset 45 | // Let's create new attribute 46 | Attribute attributeNew = dataset.createAttribute("attributeNew", 47 | DataSpace::From(string_list)); 48 | attribute.write(string_list); 49 | std::cout << "new attribute name: " << attributeNew.getName() << std::endl; 50 | std::cout << std::endl; 51 | 52 | // Move the folder with its content to other place 53 | file.rename("/NewGroup/SubGroup", "/FinalDestination"); 54 | 55 | // Here is the important moment. The old 'dataset' variable tells us 56 | // that dataset directory wasn't changed 57 | std::cout << "DataSet's path wasn't changed?" << std::endl; 58 | std::cout << "dataset path: " << dataset.getPath() << std::endl; 59 | std::cout << std::endl; 60 | 61 | // But actually it was moved we just need to update variable 62 | dataset = file.getDataSet("/FinalDestination/movedData"); 63 | std::cout << "Actually it was moved we just need to update it!" << std::endl; 64 | std::cout << "dataset path: " << dataset.getPath() << std::endl; 65 | std::cout << std::endl; 66 | 67 | file.flush(); 68 | } 69 | -------------------------------------------------------------------------------- /src/examples/select_by_id_dataset_cpp11.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | const std::string file_name("select_partial_string.h5"); 17 | const std::string dataset_name("message"); 18 | 19 | // Create a dataset name "dset" of double 4x6 20 | // 21 | int main(void) { 22 | using namespace HighFive; 23 | 24 | // Create a new file using the default property lists. 25 | File file(file_name, File::Truncate); 26 | 27 | { 28 | // We have a set of string 29 | std::vector values = { 30 | "Cat", 31 | "Dog", 32 | "Hello", 33 | "Tree", 34 | "World", 35 | "Plane", 36 | ", ", 37 | "你好", 38 | "Tea", 39 | "Moon", 40 | "صباح جميل", 41 | "Spaceship", 42 | }; 43 | 44 | // let's create a dataset 45 | DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); 46 | 47 | // and write them 48 | dataset.write(values); 49 | } 50 | 51 | { 52 | DataSet dataset = file.getDataSet(dataset_name); 53 | 54 | // now let's read back by cherry pick our interesting string 55 | std::vector result; 56 | // we select only element N° 2 and 5 57 | dataset.select(ElementSet({2, 4, 6, 7, 6, 10})).read(result); 58 | 59 | // and display it 60 | for (auto i: result) { 61 | std::cout << i << " "; 62 | } 63 | std::cout << "\n"; 64 | } 65 | 66 | return 0; // successfully terminated 67 | } 68 | -------------------------------------------------------------------------------- /src/examples/select_partial_dataset_cpp11.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017, Adrien Devresse 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | const std::string file_name("select_partial_example.h5"); 17 | const std::string dataset_name("dset"); 18 | 19 | // Create a dataset name "dset" of double 4x6 20 | // 21 | int main(void) { 22 | using namespace HighFive; 23 | 24 | // Create a new file using the default property lists. 25 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 26 | 27 | // we have some example values in a 2D vector 2x5 28 | std::vector> values = {{1.0, 2.0, 4.0, 8.0, 16.0}, 29 | {32.0, 64.0, 128.0, 256.0, 512.0}}; 30 | 31 | // let's create a dataset of this size 32 | DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); 33 | // and write them 34 | dataset.write(values); 35 | 36 | // now we read back 2x2 values after an offset of 0x2 37 | std::vector> result; 38 | dataset.select({0, 2}, {2, 2}).read(result); 39 | 40 | // we print out 4 values 41 | for (auto i: result) { 42 | for (auto j: i) { 43 | std::cout << " " << j; 44 | } 45 | std::cout << "\n"; 46 | } 47 | 48 | return 0; // successfully terminated 49 | } 50 | -------------------------------------------------------------------------------- /tests/cmake_integration/README.md: -------------------------------------------------------------------------------- 1 | # Examples of CMake Integration. 2 | This folder container examples of projects using CMake to integrate HighFive in 3 | the project. The following examples have been provided: 4 | 5 | * `application` contains an application/executable 6 | that uses HighFive and the optional Boost dependency. 7 | 8 | * `dependent_library` contains a library that uses HighFive in its API. It 9 | consists of a shared and static library; and includes, as an optional 10 | component, a Boost dependency. 11 | 12 | * `test_dependent_library` is an application to test that (or demonstrate how) 13 | `dependent_library` can be consumed easily. 14 | 15 | ## Vendoring and Integration Strategy 16 | Note that all examples have been written to pick different vendoring and 17 | integration strategies. This is for testing purposes only. Any real project 18 | would pick a single integration strategy and at most two vendoring strategies. 19 | 20 | ## Testing 21 | Run `bash test_cmake_integration.sh` to check if the CMake integration example 22 | are working as expected. 23 | -------------------------------------------------------------------------------- /tests/cmake_integration/application/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # This is an example of an application/executable using HighFive. It 2 | # demonstrates the different vendoring strategies and targets provided by 3 | # HighFive. 4 | 5 | cmake_minimum_required(VERSION 3.14) 6 | project(Hi5Application VERSION 0.1) 7 | 8 | if(NOT DEFINED CMAKE_CXX_STANDARD) 9 | set(CMAKE_CXX_STANDARD 14) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | set(CMAKE_CXX_EXTENSIONS OFF) 12 | endif() 13 | 14 | set(INTEGRATION_STRATEGY "short" CACHE STRING "Use 'Include' for HighFive::Include, 'full' for HighFive::HighFive, 'short' for HighFive.") 15 | set(VENDOR_STRATEGY "submodule" CACHE STRING "Use 'submodule' for Git submodules, 'fetch_content' for FetchContent, 'external' for `find_package`.") 16 | option(USE_STATIC_HDF5 "Link against static HDF5" OFF) 17 | option(USE_BOOST "Simulates an application using Boost" OFF) 18 | 19 | # Controlling HDF5 features is done by directly setting the HDF5 flags. The 20 | # interesting ones are probably: 21 | # * HDF5_USE_STATIC_LIBRARIES 22 | # * HDF5_PREFER_PARALLEL 23 | if(USE_STATIC_HDF5) 24 | set(HDF5_USE_STATIC_LIBRARIES On) 25 | else() 26 | set(HDF5_USE_STATIC_LIBRARIES Off) 27 | endif() 28 | 29 | if(${INTEGRATION_STRATEGY} STREQUAL "bailout") 30 | set(HIGHFIVE_FIND_HDF5 Off) 31 | endif() 32 | 33 | if(${VENDOR_STRATEGY} STREQUAL "submodule") 34 | # When vendoring via a Git submodule, this is the correct 35 | # line to include HighFive. 36 | add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) 37 | elseif(${VENDOR_STRATEGY} STREQUAL "fetch_content") 38 | include(FetchContent) 39 | FetchContent_Declare(HighFive 40 | GIT_REPOSITORY $ENV{HIGHFIVE_GIT_REPOSITORY} 41 | GIT_TAG $ENV{HIGHFIVE_GIT_TAG} 42 | ) 43 | FetchContent_MakeAvailable(HighFive) 44 | elseif(${VENDOR_STRATEGY} STREQUAL "external") 45 | # When HighFive is installed like regular software and then "found", do the 46 | # following: 47 | find_package(HighFive REQUIRED) 48 | endif() 49 | 50 | add_executable(Hi5Application "hi5_application.cpp") 51 | 52 | if( ${INTEGRATION_STRATEGY} STREQUAL "Include" 53 | OR ${INTEGRATION_STRATEGY} STREQUAL "bailout") 54 | # Only add `-I${HIGHFIVE_DIR}/include`. 55 | target_link_libraries(Hi5Application PUBLIC HighFive::Include) 56 | 57 | # Now link to HDF5 in whatever fashion you desire. 58 | find_package(HDF5 REQUIRED) 59 | target_link_libraries(Hi5Application PUBLIC HDF5::HDF5) 60 | 61 | # You might need to take care of MPI. 62 | find_package(MPI REQUIRED) 63 | target_link_libraries(Hi5Application PUBLIC MPI::MPI_C MPI::MPI_CXX) 64 | elseif(${INTEGRATION_STRATEGY} STREQUAL "short") 65 | # Highest chance of being backwards compatible with v2. 66 | target_link_libraries(Hi5Application PUBLIC HighFive) 67 | elseif(${INTEGRATION_STRATEGY} STREQUAL "full") 68 | target_link_libraries(Hi5Application PUBLIC HighFive::HighFive) 69 | endif() 70 | 71 | if(USE_BOOST) 72 | find_package(Boost REQUIRED) 73 | target_link_libraries(Hi5Application PUBLIC Boost::headers) 74 | target_compile_definitions(Hi5Application PUBLIC HI5_APPLICATION_HAS_BOOST=1) 75 | endif() 76 | 77 | if(USE_STATIC_HDF5) 78 | find_package(ZLIB REQUIRED) 79 | target_link_libraries(${target} PUBLIC ZLIB::ZLIB) 80 | endif() 81 | 82 | # Install 83 | # ------- 84 | install(TARGETS Hi5Application RUNTIME DESTINATION bin) 85 | 86 | enable_testing() 87 | add_test(NAME test_hi5_application COMMAND ${CMAKE_CURRENT_BINARY_DIR}/Hi5Application) 88 | -------------------------------------------------------------------------------- /tests/cmake_integration/application/deps/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /tests/cmake_integration/application/hi5_application.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #if HI5_APPLICATION_HAS_BOOST == 1 3 | #include 4 | #endif 5 | 6 | int main() { 7 | { 8 | auto file = HighFive::File("foo.h5", HighFive::File::Truncate); 9 | 10 | auto dset = file.createDataSet("foo", std::vector{1.0, 2.0, 3.0}); 11 | auto x = dset.read>(); 12 | 13 | for (size_t i = 0; i < x.size(); i++) { 14 | if (x[i] != double(i + 1)) { 15 | throw std::runtime_error("HighFiveDemo is broken."); 16 | } 17 | } 18 | 19 | std::cout << "Hi5Application: success \n"; 20 | } 21 | 22 | #if HI5_APPLICATION_HAS_BOOST == 1 23 | { 24 | using matrix_t = boost::numeric::ublas::matrix; 25 | 26 | auto file = HighFive::File("bar.h5", HighFive::File::Truncate); 27 | matrix_t x(3, 5); 28 | auto dset = file.createDataSet("foo", x); 29 | auto y = dset.read(); 30 | 31 | std::cout << "Hi5BoostApplication: success \n"; 32 | } 33 | #endif 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/cmake/Hi5DependentConfig.cmake.in: -------------------------------------------------------------------------------- 1 | include(CMakeFindDependencyMacro) 2 | 3 | find_dependency(HighFive) 4 | 5 | set(Hi5Dependent_INTEGRATION_STRATEGY @INTEGRATION_STRATEGY@) 6 | if( ${Hi5Dependent_INTEGRATION_STRATEGY} STREQUAL "Include" 7 | OR ${Hi5Dependent_INTEGRATION_STRATEGY} STREQUAL "bailout") 8 | # Remember to 'find' any dependencies you introduce, including HDF5 if you 9 | # use additional COMPONENTS; or MPI if you unconditionally use it. 10 | find_dependency(MPI) 11 | endif() 12 | 13 | include("${CMAKE_CURRENT_LIST_DIR}/Hi5DependentTargets.cmake") 14 | 15 | if(boost IN_LIST Hi5Dependent_FIND_COMPONENTS) 16 | set(Hi5Dependent_USE_BOOST @USE_BOOST@) 17 | 18 | if(NOT Hi5Dependent_USE_BOOST) 19 | message(FATAL_ERROR "Library was built without the component: boost") 20 | endif() 21 | 22 | find_dependency(Boost) 23 | include("${CMAKE_CURRENT_LIST_DIR}/Hi5DependentBoostTargets.cmake") 24 | endif() 25 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/include/hi5_dependent/read.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #if HI5_DEPENDENT_HAS_BOOST == 1 7 | #include 8 | #endif 9 | 10 | namespace hi5_dependent { 11 | std::vector read_vector(const HighFive::DataSet& dset); 12 | 13 | #if HI5_DEPENDENT_HAS_BOOST == 1 14 | boost::numeric::ublas::matrix read_boost(const HighFive::DataSet& dset); 15 | HighFive::DataSet write_boost(HighFive::File& file, const boost::numeric::ublas::matrix& x); 16 | #endif 17 | } // namespace hi5_dependent 18 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/include/hi5_dependent/write.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace hi5_dependent { 7 | HighFive::DataSet write_vector(HighFive::File& file, const std::vector& x); 8 | } 9 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/src/hi5_dependent/boost.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace hi5_dependent { 7 | 8 | boost::numeric::ublas::matrix read_boost(const HighFive::DataSet& dset) { 9 | return dset.read>(); 10 | } 11 | 12 | HighFive::DataSet write_boost(HighFive::File& file, 13 | const boost::numeric::ublas::matrix& x) { 14 | return file.createDataSet("foo", x); 15 | } 16 | 17 | } // namespace hi5_dependent 18 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/src/hi5_dependent/read_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace hi5_dependent { 4 | std::vector read_vector(const HighFive::DataSet& dset) { 5 | return dset.read>(); 6 | } 7 | } // namespace hi5_dependent 8 | -------------------------------------------------------------------------------- /tests/cmake_integration/dependent_library/src/hi5_dependent/write_vector.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace hi5_dependent { 4 | 5 | HighFive::DataSet write_vector(HighFive::File& file, const std::vector& x) { 6 | return file.createDataSet("foo", x); 7 | } 8 | 9 | } // namespace hi5_dependent 10 | -------------------------------------------------------------------------------- /tests/cmake_integration/test_dependent_library/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(TestHi5Dependent VERSION 0.1) 3 | 4 | if(NOT DEFINED CMAKE_CXX_STANDARD) 5 | set(CMAKE_CXX_STANDARD 14) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | set(CMAKE_CXX_EXTENSIONS OFF) 8 | endif() 9 | 10 | set(VENDOR_STRATEGY "submodule" CACHE STRING "Use 'submodule' for Git submodules, 'fetch_content' for FetchContent, 'external' for `find_package`, 'none' for making to attempt at finding HighFive.") 11 | 12 | add_executable(test_hi5_dependent test_dependent_library.cpp) 13 | 14 | if(${VENDOR_STRATEGY} STREQUAL "submodule") 15 | # When vendoring via a Git submodule, this is the correct 16 | # line to include HighFive. 17 | add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) 18 | elseif(${VENDOR_STRATEGY} STREQUAL "fetch_content") 19 | include(FetchContent) 20 | FetchContent_Declare(HighFive 21 | GIT_REPOSITORY $ENV{HIGHFIVE_GIT_REPOSITORY} 22 | GIT_TAG $ENV{HIGHFIVE_GIT_TAG} 23 | ) 24 | FetchContent_MakeAvailable(HighFive) 25 | elseif(${VENDOR_STRATEGY} STREQUAL "external") 26 | # When HighFive is installed like regular software and then "found", do the 27 | # following: 28 | find_package(HighFive REQUIRED) 29 | endif() 30 | 31 | if(NOT ${VENDOR_STRATEGY} STREQUAL "none") 32 | target_link_libraries(test_hi5_dependent PUBLIC HighFive::HighFive) 33 | endif() 34 | 35 | if(NOT USE_BOOST) 36 | find_package(Hi5Dependent REQUIRED) 37 | target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Read Hi5Dependent::Write) 38 | else() 39 | find_package(Hi5Dependent REQUIRED COMPONENTS boost) 40 | target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Read Hi5Dependent::Write) 41 | target_link_libraries(test_hi5_dependent PUBLIC Hi5Dependent::Boost) 42 | endif() 43 | 44 | enable_testing() 45 | add_test(NAME run_test_hi5_dependent COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_hi5_dependent) 46 | -------------------------------------------------------------------------------- /tests/cmake_integration/test_dependent_library/test_dependent_library.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int main() { 6 | { 7 | auto file = HighFive::File("foo.h5", HighFive::File::Truncate); 8 | 9 | auto dset = hi5_dependent::write_vector(file, {1.0, 2.0, 3.0}); 10 | auto x = hi5_dependent::read_vector(dset); 11 | 12 | for (size_t i = 0; i < x.size(); i++) { 13 | if (x[i] != double(i + 1)) { 14 | throw std::runtime_error("HighFiveDemo is broken."); 15 | } 16 | } 17 | 18 | std::cout << "Hi5Dependent: success \n"; 19 | } 20 | 21 | #if HI5_DEPENDENT_HAS_BOOST == 1 22 | { 23 | auto file = HighFive::File("bar.h5", HighFive::File::Truncate); 24 | 25 | boost::numeric::ublas::matrix x(3, 5); 26 | auto dset = hi5_dependent::write_boost(file, x); 27 | auto y = hi5_dependent::read_boost(dset); 28 | 29 | std::cout << "Hi5BoostDependent: success \n"; 30 | } 31 | #endif 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/unit/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CTest) 2 | include(Catch) 3 | 4 | if(MSVC) 5 | add_definitions(/bigobj) 6 | endif() 7 | 8 | ## Base tests 9 | foreach(test_name tests_high_five_base tests_high_five_easy test_all_types test_high_five_selection tests_high_five_data_type test_boost test_empty_arrays test_legacy test_opencv test_string test_stl test_xtensor) 10 | add_executable(${test_name} "${test_name}.cpp") 11 | target_link_libraries(${test_name} HighFive HighFiveWarnings HighFiveFlags Catch2::Catch2WithMain) 12 | target_link_libraries(${test_name} HighFiveOptionalDependencies) 13 | 14 | catch_discover_tests(${test_name}) 15 | endforeach() 16 | 17 | if(HDF5_IS_PARALLEL) 18 | set(tests_parallel_src "tests_high_five_parallel.cpp") 19 | 20 | ## parallel MPI tests 21 | add_executable(tests_parallel_bin ${tests_parallel_src}) 22 | target_link_libraries(tests_parallel_bin HighFive HighFiveWarnings Catch2::Catch2) 23 | target_link_libraries(tests_parallel_bin HighFiveOptionalDependencies) 24 | 25 | # We need to patch in a call to `mpirun` or equivalent when using 26 | # parallel tests. Somehow, this is not foreseen in Catch2, modify the 27 | # test detection script and fail if the execution method needs updating. 28 | set(original_catch_script "${_CATCH_DISCOVER_TESTS_SCRIPT}") 29 | set(patched_catch_script "${CMAKE_CURRENT_BINARY_DIR}/patched_catch_test_discovery.cmake") 30 | file(READ "${original_catch_script}" original_catch_script_contents) 31 | string(REGEX REPLACE 32 | "(add_command\\(add_test.*TEST_EXECUTOR})" 33 | "\\1 ${MPIEXEC_EXECUTABLE} ${MPIEXEC_NUMPROC_FLAG} 2" 34 | modified_catch_script_contents 35 | "${original_catch_script_contents}") 36 | if(original_catch_script_contents STREQUAL modified_catch_script_contents) 37 | message(FATAL_ERROR "Failed to modify Catch2 test execution") 38 | endif() 39 | file(WRITE "${patched_catch_script}" "${modified_catch_script_contents}") 40 | set(_CATCH_DISCOVER_TESTS_SCRIPT "${patched_catch_script}") 41 | catch_discover_tests(tests_parallel_bin) 42 | set(_CATCH_DISCOVER_TESTS_SCRIPT "${original_catch_script}") 43 | endif() 44 | 45 | # Test that each public header is self-sufficient. This is done by 46 | # creating a file for each header, that only includes the header. The 47 | # test succeeds if it compiles. 48 | file(GLOB public_headers LIST_DIRECTORIES false RELATIVE ${PROJECT_SOURCE_DIR}/include CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/include/highfive/*.hpp) 49 | foreach(PUBLIC_HEADER ${public_headers}) 50 | if(PUBLIC_HEADER STREQUAL "highfive/span.hpp" AND NOT HIGHFIVE_TEST_SPAN) 51 | continue() 52 | endif() 53 | 54 | if(PUBLIC_HEADER MATCHES "highfive/boost.*.hpp" AND NOT HIGHFIVE_TEST_BOOST) 55 | continue() 56 | endif() 57 | 58 | if(PUBLIC_HEADER STREQUAL "highfive/boost_span.hpp" AND NOT HIGHFIVE_TEST_BOOST_SPAN) 59 | continue() 60 | endif() 61 | 62 | if(PUBLIC_HEADER STREQUAL "highfive/half_float.hpp" AND NOT HIGHFIVE_TEST_HALF_FLOAT) 63 | continue() 64 | endif() 65 | 66 | if(PUBLIC_HEADER STREQUAL "highfive/eigen.hpp" AND NOT HIGHFIVE_TEST_EIGEN) 67 | continue() 68 | endif() 69 | 70 | if(PUBLIC_HEADER STREQUAL "highfive/opencv.hpp" AND NOT HIGHFIVE_TEST_OPENCV) 71 | continue() 72 | endif() 73 | 74 | if(PUBLIC_HEADER STREQUAL "highfive/xtensor.hpp" AND NOT HIGHFIVE_TEST_XTENSOR) 75 | continue() 76 | endif() 77 | 78 | get_filename_component(CLASS_NAME ${PUBLIC_HEADER} NAME_WE) 79 | configure_file(tests_import_public_headers.cpp "tests_${CLASS_NAME}.cpp" @ONLY) 80 | add_executable("tests_include_${CLASS_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/tests_${CLASS_NAME}.cpp") 81 | target_link_libraries( 82 | "tests_include_${CLASS_NAME}" PUBLIC 83 | HighFive 84 | HighFiveWarnings 85 | HighFiveFlags 86 | HighFiveOptionalDependencies 87 | ) 88 | endforeach() 89 | -------------------------------------------------------------------------------- /tests/unit/compary_arrays.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2023, 2024 Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "data_generator.hpp" 17 | 18 | namespace HighFive { 19 | namespace testing { 20 | 21 | template 22 | struct DiffMessageTrait; 23 | 24 | template 25 | struct DiffMessageTrait::value>::type> { 26 | static std::string diff(T a, T b) { 27 | std::stringstream sstream; 28 | sstream << std::scientific << " delta: " << a - b; 29 | return sstream.str(); 30 | } 31 | }; 32 | 33 | template 34 | struct DiffMessageTrait::value>::type> { 35 | static std::string diff(T /* a */, T /* b */) { 36 | return ""; 37 | } 38 | }; 39 | 40 | template 41 | std::string diff_message(T a, T b) { 42 | return DiffMessageTrait::diff(a, b); 43 | } 44 | 45 | template 46 | void compare_arrays(const Actual& actual, 47 | const Expected& expected, 48 | const std::vector& dims, 49 | Comp comp) { 50 | using actual_trait = testing::ContainerTraits; 51 | using expected_trait = testing::ContainerTraits; 52 | using base_type = typename actual_trait::base_type; 53 | 54 | auto n = testing::flat_size(dims); 55 | 56 | for (size_t i = 0; i < n; ++i) { 57 | auto indices = testing::unravel(i, dims); 58 | base_type actual_value = actual_trait::get(actual, indices); 59 | base_type expected_value = expected_trait::get(expected, indices); 60 | auto c = comp(actual_value, expected_value); 61 | if (!c) { 62 | std::stringstream sstream; 63 | sstream << std::scientific << "i = " << i << ": " << actual_value 64 | << " != " << expected_value << diff_message(actual_value, expected_value); 65 | INFO(sstream.str()); 66 | } 67 | REQUIRE(c); 68 | } 69 | } 70 | 71 | template 72 | void compare_arrays(const Actual& actual, 73 | const Expected& expected, 74 | const std::vector& dims) { 75 | using base_type = typename testing::ContainerTraits::base_type; 76 | compare_arrays(expected, actual, dims, [](base_type a, base_type b) { return a == b; }); 77 | } 78 | 79 | } // namespace testing 80 | } // namespace HighFive 81 | -------------------------------------------------------------------------------- /tests/unit/create_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace HighFive { 4 | namespace testing { 5 | 6 | /// \brief Trait for `createAttribute`. 7 | /// 8 | /// The point of these is to simplify testing. The typical issue is that we 9 | /// need to write the tests twice, one with `createDataSet` and then again with 10 | /// `createAttribute`. This trait allows us to inject this difference. 11 | struct AttributeCreateTraits { 12 | using type = Attribute; 13 | 14 | template 15 | static Attribute get(Hi5& hi5, const std::string& name) { 16 | return hi5.getAttribute(name); 17 | } 18 | 19 | 20 | template 21 | static Attribute create(Hi5& hi5, const std::string& name, const Container& container) { 22 | return hi5.createAttribute(name, container); 23 | } 24 | 25 | template 26 | static Attribute create(Hi5& hi5, 27 | const std::string& name, 28 | const DataSpace& dataspace, 29 | const DataType& datatype) { 30 | return hi5.createAttribute(name, dataspace, datatype); 31 | } 32 | 33 | template 34 | static Attribute create(Hi5& hi5, const std::string& name, const DataSpace& dataspace) { 35 | auto datatype = create_datatype(); 36 | return hi5.template createAttribute(name, dataspace); 37 | } 38 | }; 39 | 40 | /// \brief Trait for `createDataSet`. 41 | struct DataSetCreateTraits { 42 | using type = DataSet; 43 | 44 | template 45 | static DataSet get(Hi5& hi5, const std::string& name) { 46 | return hi5.getDataSet(name); 47 | } 48 | 49 | template 50 | static DataSet create(Hi5& hi5, const std::string& name, const Container& container) { 51 | return hi5.createDataSet(name, container); 52 | } 53 | 54 | template 55 | static DataSet create(Hi5& hi5, 56 | const std::string& name, 57 | const DataSpace& dataspace, 58 | const DataType& datatype) { 59 | return hi5.createDataSet(name, dataspace, datatype); 60 | } 61 | 62 | template 63 | static DataSet create(Hi5& hi5, const std::string& name, const DataSpace& dataspace) { 64 | auto datatype = create_datatype(); 65 | return hi5.template createDataSet(name, dataspace); 66 | } 67 | }; 68 | 69 | } // namespace testing 70 | } // namespace HighFive 71 | -------------------------------------------------------------------------------- /tests/unit/test_boost.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2024, Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | #if HIGHFIVE_TEST_BOOST 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | using namespace HighFive; 18 | 19 | TEST_CASE("Test boost::multi_array with fortran_storage_order") { 20 | const std::string file_name("h5_multi_array_fortran.h5"); 21 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 22 | 23 | boost::multi_array ma(boost::extents[2][2], boost::fortran_storage_order()); 24 | auto dset = file.createDataSet("main_dset", DataSpace::From(ma)); 25 | CHECK_THROWS_AS(dset.write(ma), DataTypeException); 26 | } 27 | #endif 28 | -------------------------------------------------------------------------------- /tests/unit/test_legacy.cpp: -------------------------------------------------------------------------------- 1 | // This file collects tests the require legacy behaviour of v2 (and older) to 2 | // pass. Tests in this file could be bugs too. 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | using namespace HighFive; 11 | 12 | TEST_CASE("HighFiveReadWriteConsts") { 13 | // This test seems really strange. Essentially, it malloc's a 3**3 doubles. 14 | // Then reinterpret_cast's the pointer to the first double (a `double *`) 15 | // as a `double***`. And then uses `inspector` based code to write from the 16 | // `double***`. 17 | 18 | const std::string file_name("3d_dataset_from_flat.h5"); 19 | const std::string dataset_name("dset"); 20 | const std::array DIMS{3, 3, 3}; 21 | using datatype = int; 22 | 23 | File file(file_name, File::ReadWrite | File::Create | File::Truncate); 24 | DataSpace dataspace = DataSpace(DIMS); 25 | 26 | DataSet dataset = file.createDataSet(dataset_name, dataspace); 27 | std::vector const t1(DIMS[0] * DIMS[1] * DIMS[2], 1); 28 | auto raw_3d_vec_const = reinterpret_cast(t1.data()); 29 | dataset.write_raw(raw_3d_vec_const); 30 | 31 | std::vector>> result; 32 | dataset.read(result); 33 | for (const auto& vec2d: result) { 34 | for (const auto& vec1d: vec2d) { 35 | REQUIRE(vec1d == (std::vector{1, 1, 1})); 36 | } 37 | } 38 | } 39 | 40 | TEST_CASE("Array of char pointers") { 41 | // Currently, serializing an `std::vector` as 42 | // fixed or variable length strings doesn't work. 43 | // 44 | // This isn't a test of correctness. Rather it asserts the fact that 45 | // something doesn't work in HighFive. Knowing it doesn't work is useful 46 | // for developers, but could change in the future. 47 | 48 | const std::string file_name = "vector_char_pointer.h5"; 49 | 50 | File file(file_name, File::Truncate); 51 | 52 | size_t n_strings = 3; 53 | size_t n_chars = 4; 54 | char storage[3][4] = {"foo", "bar", "000"}; 55 | auto strings = std::vector(n_strings); 56 | 57 | for (size_t i = 0; i < n_strings; ++i) { 58 | strings[i] = static_cast(storage[i]); 59 | } 60 | 61 | auto filespace = DataSpace({n_strings}); 62 | 63 | SECTION("fixed length") { 64 | auto datatype = FixedLengthStringType(n_chars, StringPadding::NullTerminated); 65 | auto dset = file.createDataSet("dset", filespace, datatype); 66 | REQUIRE_THROWS(dset.write(strings)); 67 | } 68 | 69 | SECTION("variable length") { 70 | auto datatype = VariableLengthStringType(); 71 | auto dset = file.createDataSet("dset", filespace, datatype); 72 | REQUIRE_THROWS(dset.write(strings)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tests/unit/test_opencv.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2024, Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #if HIGHFIVE_TEST_OPENCV 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include "tests_high_five.hpp" 19 | #include "create_traits.hpp" 20 | 21 | using namespace HighFive; 22 | using Catch::Matchers::Equals; 23 | 24 | TEST_CASE("OpenCV") { 25 | auto file = File("rw_opencv.h5", File::Truncate); 26 | 27 | auto a = cv::Mat_(3, 5); 28 | auto dset = file.createDataSet("a", a); 29 | auto b = dset.read>(); 30 | REQUIRE(a(0, 0) == b(0, 0)); 31 | 32 | auto va = std::vector>(7, cv::Mat_(3, 5)); 33 | auto vdset = file.createDataSet("va", va); 34 | auto vb = vdset.read>>(); 35 | REQUIRE(vb.size() == va.size()); 36 | REQUIRE(vb[0](0, 0) == va[0](0, 0)); 37 | } 38 | 39 | TEST_CASE("OpenCV subarrays") { 40 | auto file = File("rw_opencv_subarray.h5", File::Truncate); 41 | 42 | auto a = cv::Mat_(3, 13); 43 | 44 | SECTION("write") { 45 | auto sa = cv::Mat_(a.colRange(1, 4)); 46 | REQUIRE_THROWS(file.createDataSet("a", sa)); 47 | } 48 | 49 | SECTION("read") { 50 | auto b = cv::Mat_(3, 17); 51 | auto sb = cv::Mat_(a.colRange(0, 13)); 52 | auto dset = file.createDataSet("a", a); 53 | 54 | // Creates a new `Mat_` in `sb`. 55 | dset.read(sb); 56 | } 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /tests/unit/test_stl.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), 2017-2024, Blue Brain Project - EPFL 3 | * 4 | * Distributed under the Boost Software License, Version 1.0. 5 | * (See accompanying file LICENSE_1_0.txt or copy at 6 | * http://www.boost.org/LICENSE_1_0.txt) 7 | * 8 | */ 9 | 10 | #include 11 | 12 | #include 13 | 14 | 15 | #include "compary_arrays.hpp" 16 | #include "create_traits.hpp" 17 | #include "data_generator.hpp" 18 | 19 | using namespace HighFive; 20 | 21 | TEST_CASE("std::array undersized", "[stl]") { 22 | auto file = File("rw_std_array_undersized.h5", File::Truncate); 23 | auto x = std::array{1.0, 2.0, 3.0}; 24 | auto dset = file.createDataSet("x", x); 25 | 26 | REQUIRE_THROWS(dset.read>()); 27 | 28 | auto xx = std::array(); 29 | REQUIRE_THROWS(dset.read(xx)); 30 | } 31 | 32 | TEST_CASE("T[n][m]") { 33 | using reference_container = std::vector>; 34 | auto file = File("rw_carray.h5", File::Truncate); 35 | 36 | constexpr size_t n = 3; 37 | constexpr size_t m = 5; 38 | 39 | double x[n][m]; 40 | 41 | SECTION("write") { 42 | testing::initialize(x, {n, m}); 43 | 44 | auto dset = file.createDataSet("x", x); 45 | auto actual = dset.read(); 46 | 47 | testing::compare_arrays(x, actual, {n, m}); 48 | } 49 | 50 | SECTION("read") { 51 | auto expected = testing::DataGenerator::create({n, m}); 52 | 53 | auto dset = file.createDataSet("x", expected); 54 | dset.read(x); 55 | 56 | testing::compare_arrays(expected, x, {n, m}); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /tests/unit/tests_import_public_headers.cpp: -------------------------------------------------------------------------------- 1 | // This is a compilation test to be sure that public header can be included alone 2 | 3 | #include <@PUBLIC_HEADER@> 4 | 5 | int main() { 6 | return 0; 7 | } 8 | --------------------------------------------------------------------------------