diff --git a/.gitattributes b/.gitattributes index 6e07f483b..c888454a3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,59 +7,43 @@ CMakeLists.txt text eol=lf # Modern tools on Windows can handle Linux LF # See https://stackoverflow.com/a/13154031/8877 for details -* text=auto eol=lf -.git?* text +* text=auto eol=lf +*.* text=auto eol=lf +.git?* text=auto eol=lf # Leave known Windows-only text files as CR/LF -*.sln text eol=crlf -*.vcxproj text eol=crlf -*.vcxproj.filters text eol=crlf -*.ruleset text eol=crlf - -# Text file formats -*.txt text eol=lf -*.md text eol=lf -*.tex text eol=lf -*.?ml text eol=lf -*.kmz binary - -# Programming languages -*.htm? text eol=lf -*.css text eol=lf -*.c text eol=lf -*.cc text eol=lf -*.c?? text eol=lf -*.c??m text eol=lf -*.ccm text eol=lf -*.C text eol=lf -*.h?? text eol=lf -*.h text eol=lf -*.hh text eol=lf -*.ixx text eol=lf -*.mpp text eol=lf -*.py text eol=lf -*.pyc binary -# .f and .f90 -*.f* text eol=lf -*.m text eol=lf -*.java text eol=lf -*.cs text eol=lf -*.vb text eol=lf -*.js text eol=lf -*.ts text eol=lf -*.pl text eol=lf -*.sh text eol=lf -*.csh text eol=lf +*.sln text eol=crlf +*.dsw text eol=crlf +*.dsp text eol=crlf +*.vcproj text eol=crlf +*.vcxproj text eol=crlf +*.vcxproj.filters text eol=crlf +*.ruleset text eol=crlf +*.bat text eol=crlf ###################### # Known binary files +# Python builds with WAF +waf binary + +# executables, libraries; yes, sometimes they're part of a repository +*.exe binary +*.out binary +lib*.so* binary +*.dll binary +lib*.a* binary +*.lib binary +*.mex binary +*.pyc binary + # from various unit_test/ directories *.dat binary *.*hdr binary *.flat binary *.sig binary *.bin binary +*.dump binary # images *.bmp binary @@ -71,9 +55,10 @@ CMakeLists.txt text eol=lf *.jpeg binary *.png binary # SVG images are XML -*.svg text eol=lf +*.svg text *.raw binary -*.hei* binary +*.hei? binary +*.kmz binary # music *.mp3 binary @@ -90,15 +75,21 @@ CMakeLists.txt text eol=lf # documents *.pdf binary *.dvi binary -*.doc* binary -*.xls* binary -*.ppt* binary +*.doc binary +*.docx binary +*.xls binary +*.xlsx binary +*.ppt binary +*.pptx binary +# SAR *.h5 binary *.sio binary +*.hdr binary *.ntf binary *.nitf binary -*.si?d binary +*.sidd binary +*.sicd? binary # containers *.zip binary diff --git a/.github/workflows/build_unittest.yml b/.github/workflows/build_unittest.yml index 2e04ea0b2..c23bd1fbd 100644 --- a/.github/workflows/build_unittest.yml +++ b/.github/workflows/build_unittest.yml @@ -11,9 +11,9 @@ jobs: name: ${{ matrix.os }}-${{ matrix.python-version }}-CMake runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 # https://github.com/marketplace/actions/setup-python with: python-version: ${{ matrix.python-version }} - name: Install python dependencies @@ -58,24 +58,25 @@ jobs: os: [windows-latest] platform: [x64] configuration: [Debug] # Debug turns on more compiler warnings - name: ${{ matrix.os }}-msbuild + avx: [AVX2, AVX512F] + name: ${{ matrix.os }}-${{ matrix.avx }}-msbuild runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout - name: configure run: | ls env: mkdir out cd out - cmake .. -DCMAKE_INSTALL_PREFIX=install\${{ matrix.platform }}-${{ matrix.configuration }} -DENABLE_PYTHON=OFF + cmake .. -DCMAKE_INSTALL_PREFIX=install\${{ matrix.platform }}-${{ matrix.configuration }} -DENABLE_PYTHON=OFF -DENABLE_${{ matrix.avx }}=ON - name: build run: | cd out cmake --build . --config ${{ matrix.configuration }} -j cmake --build . --config ${{ matrix.configuration }} --target install - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@v1 # https://github.com/marketplace/actions/setup-msbuild + uses: microsoft/setup-msbuild@v1.1 # https://github.com/marketplace/actions/setup-msbuild with: msbuild-architecture: x64 - name: msbuild @@ -89,7 +90,7 @@ jobs: # searchFolder: D:\a\nitro\nitro\${{ matrix.platform }}\${{ matrix.configuration }} # runInParallel: true - build-linux-cmake: + build-linux-cmake-default: strategy: matrix: os: [ubuntu-latest] @@ -97,9 +98,9 @@ jobs: name: ${{ matrix.os }}-${{ matrix.python-version }}-CMake runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 # https://github.com/marketplace/actions/setup-python with: python-version: ${{ matrix.python-version }} - name: Install python dependencies @@ -109,10 +110,7 @@ jobs: run: | env which python - mkdir target - cd target - export CC=gcc-11 - export CXX=g++-11 + mkdir target && cd target cmake .. -DCMAKE_INSTALL_PREFIX=install${{ matrix.os }}CMake-Github -DPYTHON_VERSION=${{ matrix.python-version }} -DENABLE_SWIG=ON - name: build run: | @@ -129,6 +127,31 @@ jobs: cd target cmake --build . --target install + build-linux-cmake: + strategy: + matrix: + os: [ubuntu-latest] + configuration: [Debug, Release] + avx: [AVX2, AVX512F] + name: ${{ matrix.os }}-${{ matrix.configuration }}-${{ matrix.avx }}-CMake + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout + - name: configure + run: | + mkdir out && cd out + cmake .. -DENABLE_PYTHON=OFF -DENABLE_ASAN=ON -DENABLE_${{ matrix.avx }}=ON + - name: build + run: | + cd out + # "-j" spawns too many processes causing GCC to crash + cmake --build . --config ${{ matrix.configuration }} -j 12 + - name: test + # should run w/o install + run: | + cd out + ctest -C ${{ matrix.configuration }} --output-on-failure + build-waf: strategy: matrix: @@ -138,9 +161,9 @@ jobs: name: ${{ matrix.os }}-${{ matrix.python-version }}-waf${{ matrix.debugging }} runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # https://github.com/marketplace/actions/checkout - name: Set up Python - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 # https://github.com/marketplace/actions/setup-python with: python-version: ${{ matrix.python-version }} - name: configure_with_swig diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ef7c1b35..b063bbe61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,19 +24,8 @@ if (${CMAKE_PROJECT_NAME} STREQUAL coda-oss) if (MSVC) add_compile_options(/WX) # warnings as errors add_compile_options(/MP) # multi-processor compile - - if (ENABLE_ASAN) - # https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-160 - add_compile_options(/fsanitize=address) - endif() elseif (UNIX) add_compile_options(-Werror) # warnings as errors - - if (ENABLE_ASAN) - # https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html - add_compile_options(-fsanitize=address) - add_link_options(-fsanitize=address) - endif() endif() list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 845b919fc..bd37823dd 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,10 +1,21 @@ # coda-oss Release Notes +## [Release 202?-??-??](https://github.com/mdaus/coda-oss/releases/tag/202?-??-??) +* Update to [HighFive 2.8.0](https://github.com/BlueBrain/HighFive/releases/tag/v2.8.0). + +## [Release 2023-10-23](https://github.com/mdaus/coda-oss/releases/tag/2023-10-23) +* Tweaked **.gitattributes**. +* Removed *str::EncodedStringView*; made *str* conversion routines more consistent. +* *FmtX()* uses overloads rather than C-style varargs. +* Add [`std::ssize()`](https://en.cppreference.com/w/cpp/iterator/size). +* `ENABLE_AVX2` and `ENABLE_AVX512F` flags for CMake builds. +* Build cleanly with ASAN. + ## [Release 2023-08-18](https://github.com/mdaus/coda-oss/releases/tag/2023-08-18) * New `sys::OS::getSIMDInstructionSet()` utility routine; SSE2 is required (default with 64-bit builds). * `types::ComplexInteger` to work-around `std::complex` no longer being [valid C++](https://en.cppreference.com/w/cpp/numeric/complex). * Another round of reducing various compiler warnings (of note: `NULL` -> `nullptr`). -* Some suport for [`std::numbers`](https://en.cppreference.com/w/cpp/header/numbers) from C++20. +* Some support for [`std::numbers`](https://en.cppreference.com/w/cpp/header/numbers) from C++20. * Update to [HighFive 2.7.1](https://github.com/BlueBrain/HighFive/releases/tag/v2.7.1). * Update to [e2fsprogs 1.47.0](https://e2fsprogs.sourceforge.net/e2fsprogs-release.html#1.47.0). * Update to [xerces-c 3.2.4](https://issues.apache.org/jira/secure/ReleaseNote.jspa?version=12350542&styleName=Text&projectId=10510). diff --git a/UnitTest/UnitTest.vcxproj b/UnitTest/UnitTest.vcxproj index fcf23c335..237148692 100644 --- a/UnitTest/UnitTest.vcxproj +++ b/UnitTest/UnitTest.vcxproj @@ -23,7 +23,6 @@ DynamicLibrary true v143 - false Unicode @@ -31,7 +30,6 @@ false v143 true - false Unicode @@ -71,8 +69,6 @@ true /Zc:__cplusplus %(AdditionalOptions) AdvancedVectorExtensions2 - stdcpp17 - stdc11 MultiThreadedDebugDLL @@ -99,8 +95,7 @@ true /Zc:__cplusplus %(AdditionalOptions) AdvancedVectorExtensions2 - stdcpp17 - stdc11 + Speed Windows diff --git a/UnitTest/mt.cpp b/UnitTest/mt.cpp index 6be7aa933..8bbcd4356 100644 --- a/UnitTest/mt.cpp +++ b/UnitTest/mt.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "CppUnitTest.h" +#include + #include #include #include @@ -11,6 +13,7 @@ #include #include #include +#include namespace mt { diff --git a/UnitTest/sys.cpp b/UnitTest/sys.cpp index 7ac63c6a1..6561d2002 100644 --- a/UnitTest/sys.cpp +++ b/UnitTest/sys.cpp @@ -1,6 +1,8 @@ #include "pch.h" #include "CppUnitTest.h" +#include + #include #include #include diff --git a/build/scripts/makeEnums.py b/build/scripts/makeEnums.py index 911a7fefe..6e909511c 100755 --- a/build/scripts/makeEnums.py +++ b/build/scripts/makeEnums.py @@ -110,7 +110,7 @@ def cmpValues(x, y): s.write(' %sif (s == "%s")\n value = %s%s;\n' % (i > 0 and 'else ' or '', n, values.cleanPrefix, item.names[0].replace(' ', '_'))) i += 1 - s.write(' else\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %s", s.c_str())));\n') + s.write(' else\n throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %s", s.c_str())));\n') s.write(' }\n\n') s.write(' //! int constructor\n') @@ -123,7 +123,7 @@ def cmpValues(x, y): try: idx += 1 except:{} - s.write(' default:\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", i)));\n') + s.write(' default:\n throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %d", i)));\n') s.write(' }\n }\n\n') s.write(' //! destructor\n') @@ -142,7 +142,7 @@ def cmpValues(x, y): try: idx += 1 except:{} - s.write(' default:\n throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", value)));\n') + s.write(' default:\n throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %d", value)));\n') s.write(' }\n }\n\n') s.write(' //! assignment operator\n') diff --git a/cmake/CodaBuild.cmake b/cmake/CodaBuild.cmake index 69a143c1b..a74502f3c 100644 --- a/cmake/CodaBuild.cmake +++ b/cmake/CodaBuild.cmake @@ -128,8 +128,12 @@ macro(coda_initialize_build) option(BUILD_SHARED_LIBS "Build shared libraries instead of static." OFF) if(BUILD_SHARED_LIBS) set(CODA_LIBRARY_TYPE "shared") + add_definitions(-DCODA_OSS_LIBRARY_SHARED=1) + add_definitions(-UCODA_OSS_LIBRARY_STATIC) else() set(CODA_LIBRARY_TYPE "static") + add_definitions(-DCODA_OSS_LIBRARY_STATIC=1) + add_definitions(-UCODA_OSS_LIBRARY_SHARED) endif() option(CODA_BUILD_TESTS "build tests" ON) @@ -142,6 +146,17 @@ macro(coda_initialize_build) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) + # Turn on AVX2 by default ... it's from 2013. + # Well, no :-( ... it seems to cause crashes w/older + # compilers on build servers. :-( + set(ENABLE_AVX2 false) + set(ENABLE_AVX512F false) + #if (NOT ENABLE_AVX512F) + # if (NOT DISABLE_AVX2) + # set(ENABLE_AVX2 true) + # endif() + #endif() + # MSVC-specific flags and options. if (MSVC) set_property(GLOBAL PROPERTY USE_FOLDERS ON) @@ -165,6 +180,22 @@ macro(coda_initialize_build) # This should probably be replaced by GenerateExportHeader #set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD TRUE) + + if (ENABLE_ASAN) + # https://docs.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-160 + add_compile_options(/fsanitize=address) + endif() + + # Note SSE2 is implicitly enabled for x64 builds. + if (ENABLE_AVX2 AND (NOT ENABLE_AVX512F)) + # https://learn.microsoft.com/en-us/cpp/build/reference/arch-x86?view=msvc-170 + add_compile_options(/arch:AVX2) + endif() + if (ENABLE_AVX512F) + # https://learn.microsoft.com/en-us/cpp/build/reference/arch-x86?view=msvc-170 + add_compile_options(/arch:AVX512) + endif() + endif() # Unix/Linux specific options @@ -173,6 +204,27 @@ macro(coda_initialize_build) -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 ) + + if (ENABLE_ASAN) + # https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html + add_compile_options(-fsanitize=address) + add_link_options(-fsanitize=address) + endif() + + # Note SSE2 is implicitly enabled for x64 builds. + if (ENABLE_AVX2 AND (NOT ENABLE_AVX512F)) + # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html + # It doesn't look like GCC has a specific option for AVX2; + # other projects use "haswell" + add_compile_options(-march=haswell) + endif() + if (ENABLE_AVX512F) + # https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html + # It doesn't look like GCC has a specific option for AVX512F; + # other projects use "native" which isn't quite correct.' + add_compile_options(-march=native) + endif() + endif() # all targets should be installed using this export set diff --git a/modules/c++/CMakeLists.txt b/modules/c++/CMakeLists.txt index 399c82ca3..f28380ef0 100644 --- a/modules/c++/CMakeLists.txt +++ b/modules/c++/CMakeLists.txt @@ -3,19 +3,22 @@ set(TARGET_LANGUAGE c++) if (MSVC) # By default, there is a /W3 on the command-line from somewhere (?); adding # /Wn results in a compiler warning. - #add_compile_options(/W4) # /Wall - string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") # /Wall + # + # https://github.com/microsoft/STL/wiki/Changelog#vs-2022-179-preview-1 + # > *Note*: `/Wall` is not intended for regular production use, as it contains a large number of + # > extremely noisy and low-value warnings. In general, the STL does not attempt to be `/Wall` clean. + string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") # add_compile_options(/W4) elseif (UNIX) # https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html - add_compile_options(-Werror) # Make all warnings into errors + #add_compile_options(-Werror) # Make all warnings into errors add_compile_options(-Wall -Wextra -Wpedantic -pedantic-errors -Wunused) add_compile_options(-Wzero-as-null-pointer-constant) - add_compile_options(-Wsuggest-final-types -Wsuggest-final-methods) + #add_compile_options(-Wsuggest-final-types -Wsuggest-final-methods) add_compile_options(-Wsuggest-override) add_compile_options(-Woverloaded-virtual) - add_compile_options(-Warray-bounds) + #add_compile_options(-Warray-bounds) add_compile_options(-Wduplicated-branches -Wduplicated-cond) add_compile_options(-Wtrampolines) add_compile_options(-Wshadow) @@ -26,6 +29,9 @@ elseif (UNIX) add_compile_options(-Wno-double-promotion) # implicit conversion of `float` to `double` is fine + add_compile_options(-Wno-array-bounds) # TODO: fix the code! + add_compile_options(-Wno-maybe-uninitialized) # TODO: fix the code! + # Need a newer compiler than GCC 9 #add_compile_options(-Wnrvo) endif() diff --git a/modules/c++/avx/unittests/test_m256.cpp b/modules/c++/avx/unittests/test_m256.cpp index 8c6cdc47b..920a0f9f8 100644 --- a/modules/c++/avx/unittests/test_m256.cpp +++ b/modules/c++/avx/unittests/test_m256.cpp @@ -25,7 +25,9 @@ #include #include +#include #include +#include TEST_CASE(extractf) { @@ -49,8 +51,50 @@ TEST_CASE(extractf) */ TEST_SUCCESS; } + +TEST_CASE(test_getSIMDInstructionSet) +{ + // This is the reverse of getSIMDInstructionSet(): it uses the macros to generate a value. + constexpr auto simdInstructionSet = sys::getSIMDInstructionSet(); + #if __AVX512F__ + static_assert(simdInstructionSet == sys::SIMDInstructionSet::AVX512F, "getSIMDInstructionSet()"); + #elif __AVX2__ + static_assert(simdInstructionSet == sys::SIMDInstructionSet::AVX2, "getSIMDInstructionSet()"); + #else + static_assert(simdInstructionSet == sys::SIMDInstructionSet::SSE2, "getSIMDInstructionSet()"); + #endif + CODA_OSS_disable_warning_push + #if _MSC_VER + #pragma warning(disable: 4127) // conditional expression is constant + #endif + + switch (sys::getSIMDInstructionSet()) // run-time value + { + case sys::SIMDInstructionSet::SSE2: + { + TEST_ASSERT(simdInstructionSet == sys::SIMDInstructionSet::SSE2); + break; + } + case sys::SIMDInstructionSet::AVX2: + { + TEST_ASSERT(simdInstructionSet == sys::SIMDInstructionSet::AVX2); + break; + } + case sys::SIMDInstructionSet::AVX512F: + { + TEST_ASSERT(simdInstructionSet == sys::SIMDInstructionSet::AVX512F); + break; + } + default: + { + TEST_FAIL; + } + } + CODA_OSS_disable_warning_pop +} TEST_MAIN( TEST_CHECK(extractf); + TEST_CHECK(test_getSIMDInstructionSet); ) diff --git a/modules/c++/cli/include/cli/Results.h b/modules/c++/cli/include/cli/Results.h index 1a74cc7aa..bd293cf69 100644 --- a/modules/c++/cli/include/cli/Results.h +++ b/modules/c++/cli/include/cli/Results.h @@ -25,6 +25,9 @@ #define CODA_OSS_cli_Results_h_INCLUDED_ #include +#include +#include +#include #include "sys/Conf.h" @@ -33,10 +36,9 @@ namespace cli { -class Results +class Results final { -protected: - typedef std::map ValueStorage_T; + typedef std::map> ValueStorage_T; typedef ValueStorage_T::iterator ValueIter_T; typedef ValueStorage_T::const_iterator ConstValueIter_T; typedef std::map ResultsStorage_T; @@ -44,13 +46,15 @@ class Results typedef ResultsStorage_T::const_iterator ConstResultsIter_T; public: - Results() - { - } + Results() = default; ~Results() { destroy(); } + Results(const Results&) = delete; + Results& operator=(const Results&) = delete; + Results(Results&&) = default; + Results& operator=(Results&&) = default; bool hasValue(const std::string& key) const { @@ -62,20 +66,30 @@ class Results return mResults.find(key) != mResults.end(); } - cli::Value* operator[](const std::string& key) const + const cli::Value* operator[](const std::string& key) const { return getValue(key); } - cli::Value* getValue(const std::string& key) const + const cli::Value* getValue(const std::string& key) const { - ConstValueIter_T p = mValues.find(key); + auto const p = mValues.find(key); if (p == mValues.end()) { const std::string errorMessage = "No argument named " + key; throw except::NoSuchKeyException(Ctxt(errorMessage)); } - return p->second; + return p->second.get(); + } + cli::Value* getValue(const std::string& key) + { + auto const p = mValues.find(key); + if (p == mValues.end()) + { + const std::string errorMessage = "No argument named " + key; + throw except::NoSuchKeyException(Ctxt(errorMessage)); + } + return p->second.get(); } template @@ -100,15 +114,22 @@ class Results return p->second; } - void put(const std::string& key, cli::Value *value) + void put(const std::string& key, std::unique_ptr value) + { + if (hasValue(key) && (getValue(key) == value.get())) + { + return; + } + mValues[key] = std::move(value); + } + void put(const std::string& key, cli::Value* value) { - if (hasValue(key)) + cli::Value* pExistingValue = hasValue(key) ? getValue(key) : nullptr; + if ((pExistingValue == nullptr) || (pExistingValue != value)) { - cli::Value* existing = getValue(key); - if (existing != value) - delete getValue(key); + // Either 1) we didn't already have a value or 2) the existing value is different + put(key, std::unique_ptr(value)); } - mValues[key] = value; } void put(const std::string& key, cli::Results *args) @@ -122,26 +143,21 @@ class Results mResults[key] = args; } - typedef ValueStorage_T::iterator iterator; - typedef ValueStorage_T::const_iterator const_iterator; + auto begin() { return mValues.begin(); } + auto begin() const { return mValues.begin(); } + auto end() { return mValues.end(); } + auto end() const { return mValues.end(); } - iterator begin() { return mValues.begin(); } - const_iterator begin() const { return mValues.begin(); } - iterator end() { return mValues.end(); } - const_iterator end() const { return mValues.end(); } - -protected: +private: ValueStorage_T mValues; ResultsStorage_T mResults; void destroy() { - for (ValueIter_T it = mValues.begin(), end = mValues.end(); it != end; ++it) - delete it->second; + mValues.clear(); for (ResultsIter_T it = mResults.begin(), end = mResults.end(); it != end; ++it) delete it->second; - mValues.clear(); mResults.clear(); } }; diff --git a/modules/c++/cli/include/cli/Value.h b/modules/c++/cli/include/cli/Value.h index 571565cab..49f1125eb 100644 --- a/modules/c++/cli/include/cli/Value.h +++ b/modules/c++/cli/include/cli/Value.h @@ -26,6 +26,7 @@ #include #include +#include #include #include "sys/Conf.h" @@ -38,12 +39,9 @@ namespace cli * The Value class provides access to one or more actual values. * It provides index-based access to parameters. */ -class CODA_OSS_API Value +struct CODA_OSS_API Value final { -public: - Value() - { - } + Value() = default; template explicit Value(std::vector value) @@ -57,12 +55,6 @@ class CODA_OSS_API Value set(value); } - template - Value(T* value, size_t size, bool own = false) - { - set(value, size, own); - } - ~Value() { cleanup(); @@ -75,17 +67,6 @@ class CODA_OSS_API Value mValues.push_back(str::toString(value)); } - template - void set(T* value, size_t size, bool own = false) - { - cleanup(); - mValues.reserve(size); - for (size_t i = 0; i < size; ++i) - add(value[i]); - if (own) - delete[] value; - } - template void setContainer(const std::vector& c) { @@ -106,7 +87,7 @@ class CODA_OSS_API Value { if (index >= mValues.size()) throw except::IndexOutOfRangeException( - Ctxt(FmtX("Invalid index: %d", index))); + Ctxt(str::Format("Invalid index: %d", index))); return str::toType(mValues[index]); } diff --git a/modules/c++/cli/source/Argument.cpp b/modules/c++/cli/source/Argument.cpp index 01b256323..8b924f30a 100644 --- a/modules/c++/cli/source/Argument.cpp +++ b/modules/c++/cli/source/Argument.cpp @@ -54,7 +54,7 @@ cli::Argument::~Argument() cli::Argument* cli::Argument::addFlag(const std::string& flag) { char p = mParser->mPrefixChar; - std::string p2 = FmtX("%c%c", p, p); + std::string p2 = str::Format("%c%c", p, p); if (flag.size() > 2 && str::startsWith(flag, p2) && flag[2] != p) mLongFlags.push_back(validateFlag(flag.substr(2))); else if (flag.size() > 1 && flag[0] == p && flag[1] != p) diff --git a/modules/c++/cli/source/ArgumentParser.cpp b/modules/c++/cli/source/ArgumentParser.cpp index 3694e7ed3..e6c8fb444 100644 --- a/modules/c++/cli/source/ArgumentParser.cpp +++ b/modules/c++/cli/source/ArgumentParser.cpp @@ -24,13 +24,15 @@ #include #include +#include #include #include +#include namespace { -static const size_t MAX_ARG_LINE_LENGTH = 21; +constexpr size_t MAX_ARG_LINE_LENGTH = 21; bool containsOnly(const std::string& str, const std::map& flags) @@ -283,6 +285,20 @@ cli::Results* cli::ArgumentParser::parse(const std::vector& args) return parse("cli::ArgumentParser::parse" /*program*/, args).release(); // provide a "meaningful" default program name } } + +static auto put(cli::Results& currentResults, const std::string& argVar, + cli::Value* v, std::unique_ptr&& v_) +{ + if (v == v_.get()) // no existing value, using the newly created std::unique_ptr + { + currentResults.put(argVar, std::move(v_)); + } + else + { + currentResults.put(argVar, v); // already had a value, just update + } +} + std::unique_ptr cli::ArgumentParser::parse(const std::string& program, const std::vector& args) { if (!program.empty()) @@ -317,7 +333,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog std::map& flagMap = (subOption ? shortOptionsFlags : shortFlags); if (flagMap.find(op) != flagMap.end()) - parseError(FmtX("Conflicting option: %c%s", mPrefixChar, op)); + parseError(str::Format("Conflicting option: %c%s", mPrefixChar, op)); flagMap[op] = arg; } for (std::vector::const_iterator it = @@ -327,7 +343,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog std::map& flagMap = (subOption ? longOptionsFlags : longFlags); if (flagMap.find(op) != flagMap.end()) - parseError(FmtX("Conflicting option: %c%c%s", mPrefixChar, mPrefixChar, op)); + parseError(str::Format("Conflicting option: %c%c%s", mPrefixChar, mPrefixChar, op)); flagMap[op] = arg; } } @@ -456,7 +472,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog } else { - throw except::Exception(Ctxt(FmtX("Invalid option: [%s]", argStr))); + throw except::Exception(Ctxt(str::Format("Invalid option: [%s]", argStr))); } } } @@ -497,7 +513,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog } else { - throw except::Exception(Ctxt(FmtX("Invalid option: [%s]", argStr))); + throw except::Exception(Ctxt(str::Format("Invalid option: [%s]", argStr))); } } @@ -512,9 +528,8 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog { case cli::STORE: { - cli::Value* v = currentResults->hasValue(argVar) - ? currentResults->getValue(argVar) - : new cli::Value; + auto v_ = std::make_unique(); + auto v = currentResults->hasValue(argVar) ? currentResults->getValue(argVar) : v_.get(); int maxArgs = arg->getMaxArgs(); // risky, I know... bool added = false; @@ -533,8 +548,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog break; } } - if (maxArgs >= 0 && - v->size() >= static_cast(maxArgs)) + if (maxArgs >= 0 && std::ssize(*v) >= maxArgs) { // it's another positional argument, so we break out break; @@ -545,16 +559,16 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog } if (!added) - parseError(FmtX("option requires value or has exceeded its max: [%s]", argVar)); + parseError(str::Format("option requires value or has exceeded its max: [%s]", argVar)); - currentResults->put(argVar, v); + put(*currentResults, argVar, v, std::move(v_)); break; } case cli::STORE_TRUE: - currentResults->put(argVar, new cli::Value(true)); + currentResults->put(argVar, std::make_unique(true)); break; case cli::STORE_FALSE: - currentResults->put(argVar, new cli::Value(false)); + currentResults->put(argVar, std::make_unique(false)); break; case cli::STORE_CONST: { @@ -565,10 +579,10 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog case cli::SUB_OPTIONS: { if (optionsStr.empty()) - parseError(FmtX("invalid sub option: [%s]", argVar.c_str())); - cli::Value* v = currentResults->hasValue(optionsStr) - ? currentResults->getValue(optionsStr) - : new cli::Value; + parseError(str::Format("invalid sub option: [%s]", argVar)); + + auto v_ = std::make_unique(); + auto v = currentResults->hasValue(optionsStr) ? currentResults->getValue(optionsStr) : v_.get(); if (i < s - 1) { std::string nextArg = explodedArgs[i + 1]; @@ -589,7 +603,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog // this indicates the sub op is a bool v->add(true); } - currentResults->put(optionsStr, v); + put(*currentResults, optionsStr, v, std::move(v_)); break; } case cli::VERSION: @@ -601,24 +615,22 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog { // it's a positional argument cli::Value* lastPosVal = nullptr; - for (std::vector::iterator it = - positionalArgs.begin(); it != positionalArgs.end(); ++it) + for (auto&& posArg : positionalArgs) { - cli::Argument *posArg = *it; std::string argVar = posArg->getVariable(); int maxArgs = posArg->getMaxArgs(); if (currentResults->hasValue(argVar)) { - cli::Value *posVal = lastPosVal - = currentResults->getValue(argVar); - if (static_cast(posVal->size()) >= maxArgs) + lastPosVal = currentResults->getValue(argVar); + if (gsl::narrow(lastPosVal->size()) >= maxArgs) continue; break; } else if (maxArgs != 0) { - lastPosVal = new cli::Value; - currentResults->put(argVar, lastPosVal); + auto lastPosVal_ = std::make_unique(); + lastPosVal = lastPosVal_.get(); + currentResults->put(argVar, std::move(lastPosVal_)); break; } } @@ -651,12 +663,11 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog if (defaultVal != nullptr) results->put(argVar, defaultVal->clone()); else if (arg->getAction() == cli::STORE_FALSE) - results->put(argVar, new cli::Value(true)); + results->put(argVar, std::make_unique(true)); else if (arg->getAction() == cli::STORE_TRUE) - results->put(argVar, new cli::Value(false)); + results->put(argVar, std::make_unique(false)); else if (arg->isRequired()) - parseError(FmtX("missing required argument: [%s]", - argVar.c_str())); + parseError(str::Format("missing required argument: [%s]", argVar)); } @@ -670,9 +681,9 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog if (arg->isRequired() || numGiven > 0) { if (minArgs > 0 && numGiven < static_cast(minArgs)) - parseError(FmtX("not enough arguments, %d required: [%s]", minArgs, argId)); + parseError(str::Format("not enough arguments, %d required: [%s]", minArgs, argId)); if (maxArgs >= 0 && numGiven > static_cast(maxArgs)) - parseError(FmtX("too many arguments, %d supported: [%s]", maxArgs, argId)); + parseError(str::Format("too many arguments, %d supported: [%s]", maxArgs, argId)); } @@ -682,7 +693,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog if (numGiven > 0 && !choices.empty()) { bool isValid = false; - cli::Value *vals = results->getValue(argVar); + auto vals = results->getValue(argVar); for (size_t ii = 0; ii < numGiven; ++ii) { @@ -695,7 +706,7 @@ std::unique_ptr cli::ArgumentParser::parse(const std::string& prog } if (!isValid) { - parseError(FmtX("invalid option for [%s]", argVar.c_str())); + parseError(str::Format("invalid option for [%s]", argVar)); } } } diff --git a/modules/c++/cli/unittests/test_cli.cpp b/modules/c++/cli/unittests/test_cli.cpp index 62fa2192f..288df201a 100644 --- a/modules/c++/cli/unittests/test_cli.cpp +++ b/modules/c++/cli/unittests/test_cli.cpp @@ -20,12 +20,16 @@ * */ +#include + +#include +#include +#include + #include #include + #include "TestCase.h" -#include -#include -#include TEST_CASE(testValue) { @@ -41,7 +45,7 @@ TEST_CASE(testValue) for(int i = 0; i < 10; ++i) { floats.push_back(10.0f * i); - strings.push_back(str::toString(i)); + strings.push_back(std::to_string(i)); } // floats @@ -50,15 +54,15 @@ TEST_CASE(testValue) { TEST_ASSERT_ALMOST_EQ(v.at(i), 10.0f * i); } - TEST_ASSERT_EQ(v.size(), static_cast(10)); + TEST_ASSERT_EQ(std::ssize(v), 10); // strings v.setContainer(strings); for(int i = 0; i < 10; ++i) { - TEST_ASSERT_EQ(v.at(i), str::toString(i)); + TEST_ASSERT_EQ(v.at(i), std::to_string(i)); } - TEST_ASSERT_EQ(v.size(), static_cast(10)); + TEST_ASSERT_EQ(std::ssize(v), 10); } TEST_CASE(testChoices) @@ -156,9 +160,9 @@ TEST_CASE(testIterate) std::unique_ptr results(parser.parse(str::split("-v -c config.xml"))); std::vector keys; - for(cli::Results::const_iterator it = results->begin(); it != results->end(); ++it) + for(auto it = results->begin(); it != results->end(); ++it) keys.push_back(it->first); - TEST_ASSERT_EQ(keys.size(), static_cast(2)); + TEST_ASSERT_EQ(std::ssize(keys), 2); // std::map returns keys in alphabetical order... TEST_ASSERT_EQ(keys[0], "config"); TEST_ASSERT_EQ(keys[1], "verbose"); @@ -168,16 +172,25 @@ TEST_CASE(testRequired) { cli::ArgumentParser parser; parser.setProgram("tester"); - parser.addArgument("-v --verbose", "Toggle verbose", cli::STORE_TRUE); parser.addArgument("-c --config", "Specify a config file", cli::STORE)->setRequired(true); const std::string program(testName); - TEST_EXCEPTION(parser.parse(program, str::split(""))); - TEST_EXCEPTION(parser.parse(program, str::split("-c"))); const auto results = parser.parse(program, str::split("-c configFile")); TEST_ASSERT_EQ(results->get("config"), "configFile"); } +TEST_CASE(testRequiredThrows) +{ + cli::ArgumentParser parser; + parser.setProgram("tester"); + parser.addArgument("-c --config", "Specify a config file", cli::STORE) + ->setRequired(true); + + const std::string program(testName); + TEST_EXCEPTION(parser.parse(program, str::split(""))); + TEST_EXCEPTION(parser.parse(program, str::split("-c"))); +} + TEST_CASE(testUnknownArgumentsOptions) { std::ostringstream outStream; @@ -254,6 +267,7 @@ TEST_MAIN( TEST_CHECK( testSubOptions); TEST_CHECK( testIterate); TEST_CHECK( testRequired); + TEST_CHECK( testRequiredThrows); TEST_CHECK( testUnknownArgumentsOptions); ) diff --git a/modules/c++/coda-oss.vcxproj b/modules/c++/coda-oss.vcxproj index 8da940d23..17631a6b7 100644 --- a/modules/c++/coda-oss.vcxproj +++ b/modules/c++/coda-oss.vcxproj @@ -19,6 +19,8 @@ + + @@ -513,6 +515,7 @@ + @@ -568,9 +571,9 @@ - EnableAllWarnings + Level4 true - _DEBUG;_LIB;%(PreprocessorDefinitions);CODA_OSS_EXPORTS;CODA_OSS_DLL;MT_DEFAULT_PINNING=0;RE_ENABLE_STD_REGEX=1 + _DEBUG;%(PreprocessorDefinitions);MT_DEFAULT_PINNING=0;RE_ENABLE_STD_REGEX=1;CODA_OSS_EXPORTS;CODA_OSS_LIBRARY_SHARED=1 pch.h cli\include;coda_oss\include;config\include;dbi\include;except\include;gsl\include;hdf5.lite\include;io\include;logging\include;math\include;math.linear\include;math.poly\include;mem\include;mt\include;net\include;net.ssl\include;plugin\include;polygon\include;re\include;sio.lite\include;std\include;str\include;sys\include;tiff\include;types\include;unique\include;units\include;xml.lite\include;zip\include;$(ProjectDir)include;$(SolutionDir)out\install\$(Platform)-$(Configuration)\include;$(SolutionDir)externals\$(ProjectName)\out\install\$(Platform)-$(Configuration)\include Use @@ -600,11 +603,10 @@ - Level3 true true true - NDEBUG;_LIB;%(PreprocessorDefinitions);CODA_OSS_EXPORTS;CODA_OSS_DLL;MT_DEFAULT_PINNING=0;RE_ENABLE_STD_REGEX=1 + NDEBUG;%(PreprocessorDefinitions);MT_DEFAULT_PINNING=0;RE_ENABLE_STD_REGEX=1;CODA_OSS_EXPORTS;CODA_OSS_LIBRARY_SHARED=1 pch.h cli\include;coda_oss\include;config\include;dbi\include;except\include;gsl\include;hdf5.lite\include;io\include;logging\include;math\include;math.linear\include;math.poly\include;mem\include;mt\include;net\include;net.ssl\include;plugin\include;polygon\include;re\include;sio.lite\include;std\include;str\include;sys\include;tiff\include;types\include;unique\include;units\include;xml.lite\include;zip\include;$(ProjectDir)include;$(SolutionDir)out\install\$(Platform)-$(Configuration)\include;$(SolutionDir)externals\$(ProjectName)\out\install\$(Platform)-$(Configuration)\include Use @@ -616,9 +618,8 @@ true /Zc:__cplusplus %(AdditionalOptions) AdvancedVectorExtensions2 - stdcpp17 - stdc11 - true + Level3 + Speed diff --git a/modules/c++/coda-oss.vcxproj.filters b/modules/c++/coda-oss.vcxproj.filters index cfb70067f..be021bfa0 100644 --- a/modules/c++/coda-oss.vcxproj.filters +++ b/modules/c++/coda-oss.vcxproj.filters @@ -948,15 +948,11 @@ str - - - simd - - - simd + + coda_oss - - simd + + coda_oss @@ -1446,9 +1442,6 @@ {15f9b62f-d17e-4d84-bc34-de6fd5fbcb33} - - {f2544ccb-0933-44c7-af39-cd986982af3d} - {9050a469-23a5-4da0-92b1-a07a8e52e9fc} @@ -1503,8 +1496,8 @@ {59f3d9a1-06d3-4779-aef2-cc55223c3017} - - {e8e621b2-f81c-4653-9e6f-f37c2762c1a8} + + {f2544ccb-0933-44c7-af39-cd986982af3d} @@ -1572,5 +1565,8 @@ sys + + std + \ No newline at end of file diff --git a/modules/c++/coda_oss/include/coda_oss/mdspan.h b/modules/c++/coda_oss/include/coda_oss/mdspan.h new file mode 100644 index 000000000..3569440f4 --- /dev/null +++ b/modules/c++/coda_oss/include/coda_oss/mdspan.h @@ -0,0 +1,73 @@ +/* ========================================================================= + * This file is part of coda_oss-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * Copyright 2023, Maxar Technologies, Inc. + * + * coda_oss-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once + +#include "coda_oss/CPlusPlus.h" + +// This should always work ... it's in a `details` namespace +#include "coda_oss/mdspan_.h" + +// This logic needs to be here rather than so that `coda_oss::mdspan` will +// be the same as `std::mdspan`. +#ifndef CODA_OSS_HAVE_std_mdspan_ + #define CODA_OSS_HAVE_std_mdspan_ 0 // assume no +#endif +#ifndef CODA_OSS_HAVE_experimental_mdspan_ + #define CODA_OSS_HAVE_experimental_mdspan_ 0 // assume no std::experimental::mdspan +#endif +#if CODA_OSS_cpp17 // __has_include + #if __has_include() // not until C++23 + #include + #undef CODA_OSS_HAVE_std_mdspan_ + #define CODA_OSS_HAVE_std_mdspan_ 1 // provided by the implementation, probably C++23 + #endif + + #if CODA_OSS_cpp20 // Can't even #include this file with older C++14/17 compilers! :-( + // Put this in a __has_include so that it's optional. Our simple implemtnation works + // for our needs, and this brings along a lot of code that our older compilers don't + // like. By the time we need more functionality, maybe we'll be using C++23? + // + // Until then, having this available allows checking our implementation against + // something much more real. https://github.com/kokkos/mdspan + #if __has_include("coda_oss/experimental/mdspan") + #include "coda_oss/experimental/mdspan" + #undef CODA_OSS_HAVE_experimental_mdspan_ + #define CODA_OSS_HAVE_experimental_mdspan_ 1 // provided coda_oss/experimental/mdspan + #endif + #endif +#endif // CODA_OSS_cpp17 + +namespace coda_oss +{ + #if CODA_OSS_HAVE_std_mdspan_ + using std::mdspan; + using std::dextents; + #elif CODA_OSS_HAVE_experimental_mdspan_ + using std::experimental::mdspan; + using std::experimental::dextents; + #else + using details::mdspan; + using details::dextents; + #endif +} + diff --git a/modules/c++/coda_oss/include/coda_oss/mdspan_.h b/modules/c++/coda_oss/include/coda_oss/mdspan_.h new file mode 100644 index 000000000..b678051d8 --- /dev/null +++ b/modules/c++/coda_oss/include/coda_oss/mdspan_.h @@ -0,0 +1,151 @@ +/* ========================================================================= + * This file is part of coda_oss-c++ + * ========================================================================= + * + * (C) Copyright 2004 - 2014, MDA Information Systems LLC + * Copyright 2023, Maxar Technologies, Inc. + * + * coda_oss-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, + * see . + * + */ +#pragma once + +#include + +#include + +#include "coda_oss/span.h" + +// This is a simple, partial, and incomplete implementation of `std::mdspan` (in C++23). +// https://en.cppreference.com/w/cpp/container/mdspan +// +// Why? Our (current) needs are much more limited than all the use-cases for `std::mdspan`: +// dynamic (not static) extents, rank of 2 (rows cols), contiguous memory, ... +// By the time we really need more features, maybe we'll be using C++23? +namespace coda_oss +{ +namespace details +{ + // https://en.cppreference.com/w/cpp/container/mdspan/extents +template +struct dextents final // this is actually supposed to be an alias template with all dynamic extents +{ + static_assert(Rank == 2, "Rank must have a value of 2"); + using index_type = IndexType; + using size_type = index_type; + using rank_type = size_t; + + constexpr dextents() = default; + + // These are supposed to be templates, but we don't need that complication right now. + constexpr dextents(index_type i0, index_type i1) noexcept : exts_{i0, i1} + { + } + constexpr explicit dextents(const std::array& exts) noexcept : exts_(exts) + { + } + + dextents(const dextents&) = default; + dextents& operator=(const dextents&) = default; + dextents(dextents&&) = default; + dextents& operator=(dextents&&) = default; + + constexpr index_type extent(rank_type r) const noexcept + { + return exts_[r]; + } + + static constexpr auto rank() noexcept + { + return Rank; + } + +private: + std::array exts_; +}; + +template +class mdspan final +{ + coda_oss::span s_; // `span` instead of a raw pointer to get more range checking. + TExtents ext_; + + // c.f., `types::RowCol` + template + static size_t area(const dextents& exts) + { + return exts.extent(0) * exts.extent(1); + } + +public: + using extents_type = TExtents; + using size_type = typename extents_type::size_type; + using data_handle_type = T*; + using reference = T&; + + constexpr mdspan() = default; + + // Again, these are supposed to be templates ... + mdspan(data_handle_type p, const extents_type& ext) noexcept : s_(p, area(ext)), ext_(ext) + { + } + mdspan(data_handle_type p, const std::array& dims) noexcept : mdspan(p, extents_type(dims)) + { + } + + mdspan(const mdspan&) = default; + mdspan& operator=(const mdspan&) = default; + mdspan(mdspan&&) = default; + mdspan& operator=(mdspan&&) = default; + + constexpr data_handle_type data_handle() const noexcept + { + return s_.data(); + } + + /*constexpr*/ reference operator[](size_t idx) const noexcept + { + assert(idx < size()); // prevents "constexpr" in C++11 + return data_handle()[idx]; + } + /*constexpr*/ reference operator()(size_t r, size_t c) const noexcept + { + const auto offset = (r * extent(1)) + c; + return (*this)[offset]; + } + + constexpr size_t size() const noexcept + { + return s_.size(); + } + + constexpr bool empty() const noexcept + { + return s_.empty(); + } + + auto extent(size_type rank) const + { + return ext_.extent(rank); + } + + static constexpr auto rank() noexcept + { + return extents_type::rank(); + } +}; +} +} + diff --git a/modules/c++/coda_oss/include/coda_oss/optional.h b/modules/c++/coda_oss/include/coda_oss/optional.h index f1fab3a0b..86298871c 100644 --- a/modules/c++/coda_oss/include/coda_oss/optional.h +++ b/modules/c++/coda_oss/include/coda_oss/optional.h @@ -24,6 +24,9 @@ #include "coda_oss/CPlusPlus.h" +// always compile; it's in a details namespace +#include "coda_oss/optional_.h" + // This logic needs to be here rather than so that `coda_oss::optional` will // be the same as `std::optional`. #ifndef CODA_OSS_HAVE_std_optional_ @@ -37,10 +40,6 @@ #endif #endif // CODA_OSS_cpp17 -#if !CODA_OSS_HAVE_std_optional_ -#include "coda_oss/optional_.h" -#endif - namespace coda_oss { #if CODA_OSS_HAVE_std_optional_ diff --git a/modules/c++/coda_oss/include/coda_oss/span.h b/modules/c++/coda_oss/include/coda_oss/span.h index 13cb37dc4..c69d055c6 100644 --- a/modules/c++/coda_oss/include/coda_oss/span.h +++ b/modules/c++/coda_oss/include/coda_oss/span.h @@ -23,6 +23,11 @@ #ifndef CODA_OSS_coda_oss_span_h_INCLUDED_ #define CODA_OSS_coda_oss_span_h_INCLUDED_ +#include +#include +#include + +#include #include #include "coda_oss/CPlusPlus.h" @@ -90,6 +95,29 @@ inline span as_writable_bytes(span s) noexcept return span(p, s.size_bytes()); } +// https://en.cppreference.com/w/cpp/iterator/size +template +constexpr size_t size(const C& c) +{ + return c.size(); +} +template +constexpr ptrdiff_t ssize(const C& c) +{ + return gsl::narrow(c.size()); +} + +template +constexpr size_t size(const T (&)[N]) noexcept +{ + return N; +} +template +constexpr ptrdiff_t ssize(const T (&)[N]) noexcept +{ + return N; +} + } #endif // CODA_OSS_coda_oss_span_h_INCLUDED_ diff --git a/modules/c++/config/include/config/Exports.h b/modules/c++/config/include/config/Exports.h index 6b77d9fd7..71949e7c7 100644 --- a/modules/c++/config/include/config/Exports.h +++ b/modules/c++/config/include/config/Exports.h @@ -1,22 +1,30 @@ -#ifndef CODA_OSS_config_Exports_h_INCLUDED_ -#define CODA_OSS_config_Exports_h_INCLUDED_ #pragma once #include "config/compiler_extensions.h" -// Need to specify how this code will be consumed, either CODA_OSS_LIB (static library) -// or CODA_OSS_DLL (aka "shared" library). For DLLs, it needs to be set for BOTH +// Need to specify how this code will be consumed, either CODA_OSS_LIB_ (static library) +// or CODA_OSS_DLL_ (aka "shared" library). For DLLs, it needs to be set for BOTH // "exporting" (building this code) and "importing" (consuming). // // Use Windows naming conventions (DLL, LIB) because this really only matters for _MSC_VER, see below. -#if !defined(CODA_OSS_LIB) && !defined(CODA_OSS_DLL) - #define CODA_OSS_LIB 1 - //#define CODA_OSS_DLL 1 +#if !defined(CODA_OSS_LIB_) && !defined(CODA_OSS_DLL_) + #if CODA_OSS_LIBRARY_SHARED + #if CODA_OSS_LIBRARY_STATIC + #error "CODA_OSS_LIBRARY_SHARED already #define'd'" + #endif + #define CODA_OSS_DLL_ 1 // Symbols must be exported and imported (see below). + #else + // CODA_OSS_LIBRARY_STATIC doesn't have to be defined + #define CODA_OSS_LIB_ 1 // Static library, all symbols visible. + #endif #endif -#if defined(CODA_OSS_LIB) && defined(CODA_OSS_DLL) - #error "Both CODA_OSS_LIB and CODA_OSS_DLL are #define'd'" +#if !defined(CODA_OSS_LIB_) && !defined(CODA_OSS_DLL_) + #error "One of CODA_OSS_LIB_ pr CODA_OSS_DLL_ must be #define'd'" #endif -#if defined(CODA_OSS_EXPORTS) && defined(CODA_OSS_LIB) +#if defined(CODA_OSS_LIB_) && defined(CODA_OSS_DLL_) + #error "Both CODA_OSS_LIB_ and CODA_OSS_DLL_ are #define'd'" +#endif +#if defined(CODA_OSS_EXPORTS) && defined(CODA_OSS_LIB_) #error "Can't export from a LIB'" #endif @@ -35,10 +43,10 @@ // We need to know whether we're consuming (importing) a DLL or static LIB // The default is a static LIB as that's what existing code/builds expect. - #ifdef CODA_OSS_DLL + #ifdef CODA_OSS_DLL_ // Actually, it seems that the linker is able to figure this out from the .LIB, so // there doesn't seem to be a need for __declspec(dllimport). Clients don't - // need to #define CODA_OSS_DLL ... ? Well, almost ... it looks + // need to #define CODA_OSS_DLL_ ... ? Well, almost ... it looks // like __declspec(dllimport) is needed to get virtual "inline"s (e.g., // destructors) correct. #define CODA_OSS_API CODA_OSS_library_import @@ -50,5 +58,3 @@ #if defined(_MSC_VER) #pragma warning(disable: 4251) // '...' : class '...' needs to have dll-interface to be used by clients of struct '...' #endif - -#endif // CODA_OSS_config_Exports_h_INCLUDED_ diff --git a/modules/c++/config/include/config/Version.h b/modules/c++/config/include/config/Version.h index 8e3b223c3..d14635575 100644 --- a/modules/c++/config/include/config/Version.h +++ b/modules/c++/config/include/config/Version.h @@ -42,12 +42,12 @@ static_assert(CODA_OSS_MAKE_VERSION_MMPB(9999, 9999, 9999, 9999) <= UINT64_MAX, // Do this ala C++ ... we don't currently have major/minor/patch //#define CODA_OSS_VERSION_ 20210910L // c.f. __cplusplus -#define CODA_OSS_VERSION_ 2023 ## 0008 ## 0018 ## 0000 ## L +#define CODA_OSS_VERSION_ 2023 ## 0010 ## 0023 ## 0000 ## L // Use the same macros other projects might want to use; overkill for us. #define CODA_OSS_VERSION_MAJOR 2023 -#define CODA_OSS_VERSION_MINOR 8 -#define CODA_OSS_VERSION_PATCH 18 // a.k.a. "point," but too similar to "patch." +#define CODA_OSS_VERSION_MINOR 10 +#define CODA_OSS_VERSION_PATCH 23 // a.k.a. "point," but too similar to "patch." #define CODA_OSS_VERSION_BUILD 0 // a.k.a. "patch," but too similar to "point." #define CODA_OSS_VERSION CODA_OSS_MAKE_VERSION_MMPB(CODA_OSS_VERSION_MAJOR, CODA_OSS_VERSION_MINOR, CODA_OSS_VERSION_PATCH, CODA_OSS_VERSION_BUILD) diff --git a/modules/c++/dbi/tests/SQLTest1.cpp b/modules/c++/dbi/tests/SQLTest1.cpp index dbca6e5e8..ad1b0eb8d 100644 --- a/modules/c++/dbi/tests/SQLTest1.cpp +++ b/modules/c++/dbi/tests/SQLTest1.cpp @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { try { - if (argc < 4) throw except::Exception(Ctxt(FmtX("Usage %s [host] [port]", argv[0]))); + if (argc < 4) throw except::Exception(Ctxt(str::Format("Usage %s [host] [port]", argv[0]))); std::string database(argv[1]); std::string user(argv[2]); diff --git a/modules/c++/dbi/tests/SQLTest2.cpp b/modules/c++/dbi/tests/SQLTest2.cpp index 843a4d278..c1bc60f2d 100644 --- a/modules/c++/dbi/tests/SQLTest2.cpp +++ b/modules/c++/dbi/tests/SQLTest2.cpp @@ -30,7 +30,7 @@ int main(int argc, char* argv[]) { try { - if (argc != 6) throw except::Exception(Ctxt(FmtX("Usage %s ", argv[0]))); + if (argc != 6) throw except::Exception(Ctxt(str::Format("Usage %s ", argv[0]))); std::string database(argv[1]); std::string host(argv[4]); diff --git a/modules/c++/except/include/except/Context.h b/modules/c++/except/include/except/Context.h index 83f80acee..27816dcce 100644 --- a/modules/c++/except/include/except/Context.h +++ b/modules/c++/except/include/except/Context.h @@ -20,13 +20,13 @@ * */ - +#pragma once #ifndef CODA_OSS_except_Context_h_INCLUDED_ #define CODA_OSS_except_Context_h_INCLUDED_ -#pragma once #include #include +#include #include "config/Exports.h" #include "config/disable_compiler_warnings.h" @@ -59,12 +59,12 @@ struct CODA_OSS_API Context final Context(const char* file /*__FILE__*/, int line /*__LINE__*/, const std::string& func, const std::string& time, - const std::string& message = "") : - mMessage(message), - mTime(time), - mFunc(func), - mFile(file), - mLine(line) { } + const std::string& message = "" /*for existing SWIG bindings*/) + : mMessage(message), mTime(time), mFunc(func), mFile(file), mLine(line) { } + Context(const char* file /*__FILE__*/, int line /*__LINE__*/, + const std::string& func, + const std::string& time, + const std::ostringstream& message) : Context(file, line, func, time, message.str()) { } Context(const std::string& message, const char* file /*__FILE__*/, int line /*__LINE__*/, const std::string& func = "", diff --git a/modules/c++/gsl/CMakeLists.txt b/modules/c++/gsl/CMakeLists.txt index 6f17aa779..10d694163 100644 --- a/modules/c++/gsl/CMakeLists.txt +++ b/modules/c++/gsl/CMakeLists.txt @@ -4,5 +4,3 @@ coda_add_module( ${MODULE_NAME} VERSION 1.0 DEPS config-c++) - - diff --git a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h index 9392890bb..aea2d9c51 100644 --- a/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h +++ b/modules/c++/hdf5.lite/include/hdf5/lite/SpanRC.h @@ -20,22 +20,11 @@ * */ +#pragma once #ifndef CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ #define CODA_OSS_hdf5_lite_SpanRC_h_INCLUDED_ -#pragma once -/*! - * \file SpanRC.h - * - * This is a super-simple version of C++23's mdspan. It's here because 1) don't want widespread use, and - * 2) CODA already has a View2D. - */ - -#include - -#include "config/Exports.h" -#include "coda_oss/span.h" -#include "types/RowCol.h" +#include "coda_oss/mdspan.h" namespace hdf5 { @@ -43,71 +32,7 @@ namespace lite { template -struct SpanRC final -{ - using size_type = types::RowCol; - using element_type = T; - using pointer = T*; - using reference = T&; - - SpanRC() = default; - SpanRC(pointer p, size_type rc) noexcept : s_(p, rc.area()), rc_(rc) - { - } - SpanRC(pointer p, size_t r, size_t c) noexcept : SpanRC(p, size_type(r, c)) - { - } - SpanRC(const SpanRC&) noexcept = default; - - constexpr pointer data() const noexcept - { - return s_.data(); - } - - /*constexpr*/ reference operator[](size_t idx) const noexcept - { - assert(idx < size()); // prevents "constexpr" in C++11 - return data()[idx]; - } - /*constexpr*/ reference operator()(size_t r, size_t c) const noexcept - { - const auto offset = (r * dims().col) + c; - return (*this)[offset]; - } - /*constexpr*/ reference operator[](size_type idx) const noexcept - { - return (*this)(idx.row, idx.col); - } - - constexpr size_t size() const noexcept - { - assert(s_.size() == rc_.area()); - return s_.size(); - } - constexpr size_t area() const noexcept - { - return size(); - } - - constexpr size_type size_bytes() const noexcept - { - return s_.size_bytes(); - } - - constexpr bool empty() const noexcept - { - return s_.empty(); - } - - const auto& dims() const - { - return rc_; - } - - private: - coda_oss::span s_; - types::RowCol rc_; -}; +using SpanRC = coda_oss::mdspan>; } } diff --git a/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h b/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h index fb276e681..c93d5a9a4 100644 --- a/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h +++ b/modules/c++/hdf5.lite/include/hdf5/lite/highfive.h @@ -33,6 +33,8 @@ #include #include +#include "types/RowCol.h" + #include "H5_.h" #include "SpanRC.h" @@ -56,10 +58,10 @@ inline auto vv_load(const H5Easy::File& file, const std::string& dataset_name) template inline HighFive::DataSet writeDataSet(H5Easy::File& file, const std::string& dataset_name, SpanRC data /*, TODO ...*/) { - const std::vector dims{data.dims().row, data.dims().col}; + const std::vector dims{data.extent(0), data.extent(1)}; const HighFive::DataSpace dataspace{dims}; auto retval = file.createDataSet(dataset_name, dataspace); - retval.write_raw(data.data()); + retval.write_raw(data.data_handle()); return retval; } @@ -87,7 +89,7 @@ inline SpanRC readDataSet(const HighFive::DataSet& dataSet, std::vector& r result.resize(dims.area()); dataSet.read(result.data()); - return SpanRC(result.data(), dims); + return SpanRC(result.data(), std::array{dims.row, dims.col}); } template diff --git a/modules/c++/hdf5.lite/unittests/test_highfive.cpp b/modules/c++/hdf5.lite/unittests/test_highfive.cpp index 3ca66b89a..9fbfd7654 100644 --- a/modules/c++/hdf5.lite/unittests/test_highfive.cpp +++ b/modules/c++/hdf5.lite/unittests/test_highfive.cpp @@ -53,10 +53,11 @@ TEST_CASE(test_highfive_load) { std::vector lat; const auto rc = hdf5::lite::loadDataSet(file, "/g4/lat", lat); + static_assert(decltype(rc)::rank() == 2, "wrong rank()"); TEST_ASSERT_EQ(lat.size(), 19); - TEST_ASSERT_EQ(lat.size(), rc.area()); - TEST_ASSERT_EQ(rc.dims().row, 19); - TEST_ASSERT_EQ(rc.dims().col, 1); + TEST_ASSERT_EQ(lat.size(), rc.size()); + TEST_ASSERT_EQ(rc.extent(0), 19); + TEST_ASSERT_EQ(rc.extent(1), 1); TEST_ASSERT_ALMOST_EQ(lat[0], -90.0); TEST_ASSERT_ALMOST_EQ(lat[0], -lat[18]); } @@ -103,9 +104,9 @@ template static auto read_complex(const HighFive::DataSet& r, const HighFive::DataSet& i) { std::vector r_result; - hdf5::lite::readDataSet(r, r_result); + std::ignore = hdf5::lite::readDataSet(r, r_result); std::vector i_result; - hdf5::lite::readDataSet(i, i_result); + std::ignore = hdf5::lite::readDataSet(i, i_result); return std::make_pair(r, i); } template @@ -405,11 +406,11 @@ TEST_CASE(test_highfive_write) const types::RowCol dims{10, 20}; std::vector data_(dims.area()); - const hdf5::lite::SpanRC data(data_.data(), dims); + hdf5::lite::SpanRC data(data_.data(), std::array{dims.row, dims.col}); double d = 0.0; - for (size_t r = 0; r result; const auto rc = hdf5::lite::loadDataSet(file, "/DS1", result); - TEST_ASSERT(rc.dims() == dims); + TEST_ASSERT(rc.extent(0) == dims.row); + TEST_ASSERT(rc.extent(1) == dims.col); TEST_ASSERT_EQ(dims.area(), result.size()); for (size_t i = 0; i < result.size(); i++) { @@ -560,7 +562,7 @@ TEST_MAIN( TEST_CHECK(test_highfive_info_nested); TEST_CHECK(test_highfive_dump); - //TEST_CHECK(test_highfive_write); + TEST_CHECK(test_highfive_write); TEST_CHECK(test_highfive_getDataType); TEST_CHECK(test_highfive_getAttribute); diff --git a/modules/c++/include/TestCase.h b/modules/c++/include/TestCase.h index b572b7c4d..08aa1a4fd 100644 --- a/modules/c++/include/TestCase.h +++ b/modules/c++/include/TestCase.h @@ -20,9 +20,9 @@ * */ -#ifndef __TEST_CASE_H__ -#define __TEST_CASE_H__ #pragma once +#ifndef CODA_OSS_TestCase_h_INCLUDED_ +#define CODA_OSS_TestCase_h_INCLUDED_ #ifdef __cplusplus @@ -75,6 +75,10 @@ inline std::string toString(const TX& X) { return str::toString(X); } +inline std::string toString(const coda_oss::u8string& X) +{ + return str::to_native(X); +} template inline void diePrintf_(const char* format, const std::string& testName, const char* file, const char* func, int line, @@ -276,4 +280,4 @@ inline int main(TFunc f) #endif -#endif +#endif // CODA_OSS_TestCase_h_INCLUDED_ diff --git a/modules/c++/include/UnitTest.h b/modules/c++/include/UnitTest.h index b99a2cde4..2ca366b68 100644 --- a/modules/c++/include/UnitTest.h +++ b/modules/c++/include/UnitTest.h @@ -132,7 +132,7 @@ inline void assert_almost_eq(const std::string& testName, long double X1, long d #define TEST_ASSERT_EQ_MSG(msg, X1, X2) testName, Microsoft::VisualStudio::CppUnitTestFramework::Logger::WriteMessage(msg.c_str()); TEST_ASSERT_EQ(X1, X2) #undef TEST_FAIL_MSG -#define TEST_FAIL_MSG(msg) { (void)testName; Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail(str::toWString(msg).c_str()); } +#define TEST_FAIL_MSG(msg) { (void)testName; Microsoft::VisualStudio::CppUnitTestFramework::Assert::Fail(str::details::to_wstring(msg).c_str()); } #undef TEST_EXCEPTION #undef TEST_THROWS diff --git a/modules/c++/io/include/io/BufferViewStream.h b/modules/c++/io/include/io/BufferViewStream.h index beb00d23a..5f71ae46c 100644 --- a/modules/c++/io/include/io/BufferViewStream.h +++ b/modules/c++/io/include/io/BufferViewStream.h @@ -191,7 +191,7 @@ void BufferViewStream::write(const void* buffer, size_t numBytes) { std::ostringstream msg; msg << "Write of size " << numBytes << " runs out of bounds."; - throw except::Exception(Ctxt(msg.str())); + throw except::Exception(Ctxt(msg)); } ::memcpy(mBufferView.data + mPosition, buffer, numBytes); diff --git a/modules/c++/io/include/io/ByteStream.h b/modules/c++/io/include/io/ByteStream.h index a64b7efc8..c8fc32a06 100644 --- a/modules/c++/io/include/io/ByteStream.h +++ b/modules/c++/io/include/io/ByteStream.h @@ -117,10 +117,13 @@ struct CODA_OSS_API ByteStream : public SeekableInputStream, public SeekableOutp return mData.empty() ? nullptr : &mData[0]; } - sys::Size_T - getSize() + auto size() const { - return mData.size(); + return mData.size(); + } + auto getSize() const + { + return size(); } protected: diff --git a/modules/c++/io/include/io/FileUtils.h b/modules/c++/io/include/io/FileUtils.h index d8305fc0c..927aeb4f5 100644 --- a/modules/c++/io/include/io/FileUtils.h +++ b/modules/c++/io/include/io/FileUtils.h @@ -62,7 +62,7 @@ inline void move(const std::string& path, oss << "Move Failed: Could not move source [" << path << "] to destination [" << newPath << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } diff --git a/modules/c++/io/include/io/Serializable.h b/modules/c++/io/include/io/Serializable.h index e6d2363ae..4db6eeab7 100644 --- a/modules/c++/io/include/io/Serializable.h +++ b/modules/c++/io/include/io/Serializable.h @@ -19,10 +19,12 @@ * see . * */ - +#pragma once #ifndef __IO_SERIALIZABLE_H__ #define __IO_SERIALIZABLE_H__ +#include "config/Exports.h" + #include "io/InputStream.h" #include "io/OutputStream.h" @@ -46,7 +48,7 @@ namespace io * This object has a known derived type SOAPMessage, which is concretely * defined to handle SOAP objects */ -struct Serializable +struct CODA_OSS_API Serializable { Serializable() = default; virtual ~Serializable() noexcept(false) {} diff --git a/modules/c++/io/source/ByteStream.cpp b/modules/c++/io/source/ByteStream.cpp index bffd24aa1..7383011e4 100644 --- a/modules/c++/io/source/ByteStream.cpp +++ b/modules/c++/io/source/ByteStream.cpp @@ -20,6 +20,8 @@ * */ +#include + #include "io/ByteStream.h" sys::Off_T io::ByteStream::seek(sys::Off_T offset, Whence whence) @@ -33,13 +35,13 @@ sys::Off_T io::ByteStream::seek(sys::Off_T offset, Whence whence) mPosition = offset; break; case END: - if (offset > static_cast(mData.size())) + if (offset > std::ssize(mData)) { mPosition = 0; } else { - mPosition = static_cast(mData.size() - offset); + mPosition = std::ssize(mData) - offset; } break; case CURRENT: @@ -48,7 +50,7 @@ sys::Off_T io::ByteStream::seek(sys::Off_T offset, Whence whence) break; } - if (mPosition > static_cast(mData.size())) + if (mPosition > std::ssize(mData)) mPosition = -1; return tell(); } @@ -59,7 +61,7 @@ sys::Off_T io::ByteStream::available() throw except::Exception(Ctxt("Invalid available bytes on eof")); sys::Off_T where = mPosition; - sys::Off_T until = static_cast(mData.size()); + sys::Off_T until = std::ssize(mData); sys::Off_T diff = until - where; return (diff < 0) ? 0 : diff; } @@ -78,7 +80,7 @@ void io::ByteStream::write(const void* buffer, sys::Size_T size) mData.resize(newPos); const auto bufferPtr = static_cast(buffer); - std::copy(bufferPtr, bufferPtr + size, &mData[static_cast(mPosition)]); + std::copy(bufferPtr, bufferPtr + size, &mData[gsl::narrow(mPosition)]); mPosition = static_cast(newPos); } } diff --git a/modules/c++/io/source/FileInputStreamIOS.cpp b/modules/c++/io/source/FileInputStreamIOS.cpp index e1585d16b..5ff403893 100644 --- a/modules/c++/io/source/FileInputStreamIOS.cpp +++ b/modules/c++/io/source/FileInputStreamIOS.cpp @@ -91,7 +91,7 @@ void io::FileInputStreamIOS::open(const char *file, mFStream.open(file, mode); if (!isOpen()) throw except::IOException(Ctxt( - FmtX( + str::Format( "File %s could not be opened for reading", file) ) diff --git a/modules/c++/io/source/FileUtils.cpp b/modules/c++/io/source/FileUtils.cpp index 9de78af1f..5e34ef8cc 100644 --- a/modules/c++/io/source/FileUtils.cpp +++ b/modules/c++/io/source/FileUtils.cpp @@ -122,7 +122,7 @@ void io::copy(const std::string& path, oss << "Copy Failed: Could not copy source [" << path << "] to destination [" << newFile << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } } @@ -133,8 +133,7 @@ std::string io::FileUtils::createFile(std::string dirname, sys::OS os; if (!os.exists(dirname)) - throw except::IOException(Ctxt(FmtX("Directory does not exist: %s", - dirname.c_str()))); + throw except::IOException(Ctxt(str::Format("Directory does not exist: %s", dirname))); str::trim(filename); @@ -155,7 +154,7 @@ std::string io::FileUtils::createFile(std::string dirname, int count = 0; while (os.exists(outFilename)) { - std::string base = filename + "-" + str::toString(++count); + std::string base = filename + "-" + std::to_string(++count); outFilename = sys::Path::joinPaths(dirname, base); if (!ext.empty()) { diff --git a/modules/c++/io/source/InputStream.cpp b/modules/c++/io/source/InputStream.cpp index e39ac48a6..b85dcf37d 100644 --- a/modules/c++/io/source/InputStream.cpp +++ b/modules/c++/io/source/InputStream.cpp @@ -37,14 +37,14 @@ sys::SSize_T InputStream::read(void* buffer, { std::ostringstream ostr; ostr << "Tried to read " << len << " bytes but read failed"; - throw except::IOException(Ctxt(ostr.str())); + throw except::IOException(Ctxt(ostr)); } else if (numBytes != static_cast(len)) { std::ostringstream ostr; ostr << "Tried to read " << len << " bytes but only read " << numBytes << " bytes"; - throw except::IOException(Ctxt(ostr.str())); + throw except::IOException(Ctxt(ostr)); } } diff --git a/modules/c++/io/source/MMapInputStream.cpp b/modules/c++/io/source/MMapInputStream.cpp index d942ac223..35959ef01 100644 --- a/modules/c++/io/source/MMapInputStream.cpp +++ b/modules/c++/io/source/MMapInputStream.cpp @@ -28,7 +28,7 @@ void io::MMapInputStream::open(const std::string& fname, char* flags) // std::cout << mLength << std::endl; mFile = fopen(fname.c_str(), "r"); if (!mFile) - throw sys::SystemException(FmtX("Failure while opening file: %s", fname.c_str())); + throw sys::SystemException(str::Format("Failure while opening file: %s", fname)); _map(); diff --git a/modules/c++/io/source/RotatingFileOutputStream.cpp b/modules/c++/io/source/RotatingFileOutputStream.cpp index 777c60c00..67a431e53 100644 --- a/modules/c++/io/source/RotatingFileOutputStream.cpp +++ b/modules/c++/io/source/RotatingFileOutputStream.cpp @@ -28,10 +28,11 @@ io::RotatingFileOutputStream::RotatingFileOutputStream( unsigned long maxBytes, size_t backupCount, int creationFlags) : - io::CountingOutputStream(new io::FileOutputStream(filename, creationFlags), - true), mFilename(filename), mMaxBytes(maxBytes), - mBackupCount(backupCount) + io::CountingOutputStream(new io::FileOutputStream(filename, creationFlags), true), + mMaxBytes(maxBytes), mBackupCount(backupCount) { + mFilename = filename; // doing this in initializer list causes ASAN diagnostic on Windows ... VS bug? + mByteCount = ((io::FileOutputStream*) mProxy.get())->tell(); if (shouldRollover(0)) doRollover(); diff --git a/modules/c++/io/source/StandardStreams.cpp b/modules/c++/io/source/StandardStreams.cpp index 232361399..3e374d09d 100644 --- a/modules/c++/io/source/StandardStreams.cpp +++ b/modules/c++/io/source/StandardStreams.cpp @@ -33,7 +33,7 @@ void io::StandardOutStream::write(const void* buffer, sys::Size_T len) if (!std::cout.good()) throw except::IOException( Ctxt( - FmtX("std::cout stream is bad after requested write: (%d)", + str::Format("std::cout stream is bad after requested write: (%d)", len)) ); } @@ -53,7 +53,7 @@ void io::StandardErrStream::write(const void* buffer, sys::Size_T len) if (!std::cerr.good()) throw except::IOException( Ctxt( - FmtX("std::cerr stream is bad after requested write: (%d)", + str::Format("std::cerr stream is bad after requested write: (%d)", len) ) ); } diff --git a/modules/c++/io/source/StreamSplitter.cpp b/modules/c++/io/source/StreamSplitter.cpp index 57d6a2f60..dbef8edc2 100644 --- a/modules/c++/io/source/StreamSplitter.cpp +++ b/modules/c++/io/source/StreamSplitter.cpp @@ -55,7 +55,7 @@ StreamSplitter::StreamSplitter(io::InputStream& inputStream, std::ostringstream os; os << "bufferSize must be >= twice the delimiter size + 1 byte. " << "Normally it should be much larger for good performance."; - throw except::InvalidArgumentException(Ctxt(os.str())); + throw except::InvalidArgumentException(Ctxt(os)); } } diff --git a/modules/c++/io/tests/ioTest1.cpp b/modules/c++/io/tests/ioTest1.cpp index 56cd99924..f803f47e8 100644 --- a/modules/c++/io/tests/ioTest1.cpp +++ b/modules/c++/io/tests/ioTest1.cpp @@ -33,7 +33,7 @@ int main(int argc, char **argv) { if (argc != 3) { - throw Exception(Ctxt(FmtX("Usage: %s ", + throw Exception(Ctxt(str::Format("Usage: %s ", argv[0]))); } diff --git a/modules/c++/io/tests/ioTest3.cpp b/modules/c++/io/tests/ioTest3.cpp index 39a85190b..f00693da4 100644 --- a/modules/c++/io/tests/ioTest3.cpp +++ b/modules/c++/io/tests/ioTest3.cpp @@ -48,7 +48,7 @@ int main(int argc, char **argv) try { if (argc != 3) - throw Exception(Ctxt(FmtX("Usage: %s ", argv[0]))); + throw Exception(Ctxt(str::Format("Usage: %s ", argv[0]))); Copy::run(argv[1], argv[2]); } diff --git a/modules/c++/io/tests/ioTest4.cpp b/modules/c++/io/tests/ioTest4.cpp index a45f89b7f..7121f9b0e 100644 --- a/modules/c++/io/tests/ioTest4.cpp +++ b/modules/c++/io/tests/ioTest4.cpp @@ -53,7 +53,7 @@ int main(int argc, char **argv) if (argc != 3) throw except::Error( Ctxt( - FmtX( + str::Format( "Usage: %s ", argv[0]))); diff --git a/modules/c++/io/tests/serializeTest1.cpp b/modules/c++/io/tests/serializeTest1.cpp index 2037899ae..5229fb265 100644 --- a/modules/c++/io/tests/serializeTest1.cpp +++ b/modules/c++/io/tests/serializeTest1.cpp @@ -47,9 +47,9 @@ class A : public Serializable virtual void serialize(OutputStream& os) override { os.writeln("Class A"); - os.writeln(FmtX("%f", vec[0])); - os.writeln(FmtX("%f", vec[1])); - os.writeln(FmtX("%f", vec[2])); + os.writeln(str::Format("%f", vec[0])); + os.writeln(str::Format("%f", vec[1])); + os.writeln(str::Format("%f", vec[2])); } virtual void deserialize(InputStream& is) override @@ -60,9 +60,9 @@ class A : public Serializable string vec_2 = fillString(is); assert(classType == "Class A"); - dbg.writeln(FmtX("vec[0] = %s", vec_0.c_str())); - dbg.writeln(FmtX("vec[1] = %s", vec_1.c_str())); - dbg.writeln(FmtX("vec[2] = %s", vec_2.c_str())); + dbg.writeln(str::Format("vec[0] = %s", vec_0)); + dbg.writeln(str::Format("vec[1] = %s", vec_1)); + dbg.writeln(str::Format("vec[2] = %s", vec_2)); vec[0] = str::toType(vec_0); vec[1] = str::toType(vec_1); diff --git a/modules/c++/io/unittests/test_streams.cpp b/modules/c++/io/unittests/test_streams.cpp index 63587403e..ce253f7e3 100644 --- a/modules/c++/io/unittests/test_streams.cpp +++ b/modules/c++/io/unittests/test_streams.cpp @@ -80,10 +80,10 @@ TEST_CASE(testByteStream) stream.seek(2, io::Seekable::END); TEST_ASSERT_EQ(stream.tell(), 18); - TEST_ASSERT_EQ(stream.getSize(), static_cast(20)); + TEST_ASSERT_EQ(std::ssize(stream), 20); stream.write("abcdef"); - TEST_ASSERT_EQ(stream.getSize(), static_cast(24)); + TEST_ASSERT_EQ(std::ssize(stream), 24); const std::string test("test"); { @@ -259,8 +259,8 @@ TEST_CASE(testRotate) for(size_t i = 0; i < maxFiles - 1; ++i) { - std::string fname = outFile + "." + str::toString(i + 1); - std::string next = outFile + "." + str::toString(i + 2); + std::string fname = outFile + "." + std::to_string(i + 1); + std::string next = outFile + "." + std::to_string(i + 2); TEST_ASSERT(os.isFile(fname)); TEST_ASSERT_FALSE(os.isFile(next)); diff --git a/modules/c++/logging/include/logging/Enums.h b/modules/c++/logging/include/logging/Enums.h index f7d30fb1e..9175a8126 100644 --- a/modules/c++/logging/include/logging/Enums.h +++ b/modules/c++/logging/include/logging/Enums.h @@ -93,7 +93,7 @@ struct LogLevel final else if (s == "SEVERE") value = LOG_CRITICAL; else - throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %s", s.c_str()))); + throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %s", s))); } //! int constructor @@ -120,7 +120,7 @@ struct LogLevel final value = LOG_CRITICAL; break; default: - throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", i))); + throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %d", i))); } } @@ -145,7 +145,7 @@ struct LogLevel final case 5: return std::string("CRITICAL"); default: - throw except::InvalidFormatException(Ctxt(FmtX("Invalid enum value: %d", value))); + throw except::InvalidFormatException(Ctxt(str::Format("Invalid enum value: %d", value))); } } diff --git a/modules/c++/logging/include/logging/Logger.h b/modules/c++/logging/include/logging/Logger.h index df158fcfc..2b33c9065 100644 --- a/modules/c++/logging/include/logging/Logger.h +++ b/modules/c++/logging/include/logging/Logger.h @@ -24,12 +24,14 @@ // Logger.h /////////////////////////////////////////////////////////// +#pragma once #ifndef CODA_OSS_logging_Logger_h_INCLUDED_ #define CODA_OSS_logging_Logger_h_INCLUDED_ #include #include #include +#include #include "config/Exports.h" #include "logging/Filterer.h" @@ -79,6 +81,17 @@ struct CODA_OSS_API Logger : public Filterer //! Logs a message at the CRITICAL LogLevel void critical(const std::string& msg); + //! Logs a message at the DEBUG LogLevel + void debug(const std::ostringstream& msg); + //! Logs a message at the INFO LogLevel + void info(const std::ostringstream& msg); + //! Logs a message at the WARNING LogLevel + void warn(const std::ostringstream& msg); + //! Logs a message at the ERROR LogLevel + void error(const std::ostringstream& msg); + //! Logs a message at the CRITICAL LogLevel + void critical(const std::ostringstream& msg); + //! Logs an Exception Context at the DEBUG LogLevel void debug(const except::Context& ctxt); //! Logs an Exception Context at the INFO LogLevel diff --git a/modules/c++/logging/include/logging/Setup.h b/modules/c++/logging/include/logging/Setup.h index ae0d4caca..7d14baafe 100644 --- a/modules/c++/logging/include/logging/Setup.h +++ b/modules/c++/logging/include/logging/Setup.h @@ -20,6 +20,7 @@ * */ +#pragma once #ifndef CODA_OSS_logging_Setup_h_INCLUDED_ #define CODA_OSS_logging_Setup_h_INCLUDED_ @@ -30,6 +31,7 @@ #include "mem/SharedPtr.h" #include "logging/Logger.h" #include "sys/filesystem.h" +#include "config/Exports.h" namespace logging { @@ -49,8 +51,8 @@ using path = coda_oss::filesystem::path; // still used in SWIG bindings * \param logCount - number of rotating logs to keep (default: 0 no rotation) * \param logBytes - number of bytes per rotating log (default: 0 no rotation) */ -std::unique_ptr setupLogger( - const std::filesystem::path& program, +CODA_OSS_API std::unique_ptr setupLogger( + const path& program, const std::string& logLevel = "warning", const std::filesystem::path& logFile = "console", const std::string& logFormat = "[%p] (%d) %m", diff --git a/modules/c++/logging/source/Logger.cpp b/modules/c++/logging/source/Logger.cpp index 9fa37642f..3f3837537 100644 --- a/modules/c++/logging/source/Logger.cpp +++ b/modules/c++/logging/source/Logger.cpp @@ -98,6 +98,30 @@ void logging::Logger::critical(const std::string& msg) log(LogLevel::LOG_CRITICAL, msg); } +void logging::Logger::debug(const std::ostringstream& msg) +{ + log(LogLevel::LOG_DEBUG, msg.str()); +} + +void logging::Logger::info(const std::ostringstream& msg) +{ + log(LogLevel::LOG_INFO, msg.str()); +} + +void logging::Logger::warn(const std::ostringstream& msg) +{ + log(LogLevel::LOG_WARNING, msg.str()); +} + +void logging::Logger::error(const std::ostringstream& msg) +{ + log(LogLevel::LOG_ERROR, msg.str()); +} + +void logging::Logger::critical(const std::ostringstream& msg) +{ + log(LogLevel::LOG_CRITICAL, msg.str()); +} void logging::Logger::debug(const except::Context& ctxt) { diff --git a/modules/c++/logging/source/Setup.cpp b/modules/c++/logging/source/Setup.cpp index e1a7e6491..b1a13ec64 100644 --- a/modules/c++/logging/source/Setup.cpp +++ b/modules/c++/logging/source/Setup.cpp @@ -35,7 +35,7 @@ std::unique_ptr logging::setupLogger(const std::filesystem::path& program_, const std::string& logLevel, - const std::filesystem::path& logFile_, + const path& logFile, const std::string& logFormat, size_t logCount, size_t logBytes) @@ -44,30 +44,25 @@ logging::setupLogger(const std::filesystem::path& program_, std::unique_ptr log(new logging::Logger(program)); // setup logging level - std::string lev = logLevel; - str::upper(lev); + auto lev = str::upper(logLevel); str::trim(lev); - logging::LogLevel level = (lev.empty()) ? logging::LogLevel::LOG_WARNING : - logging::LogLevel(lev); + const auto level = lev.empty() ? logging::LogLevel::LOG_WARNING : logging::LogLevel(lev); // setup logging formatter std::unique_ptr formatter; - const auto logFile = logFile_.string(); - auto file = logFile; - str::lower(file); + const auto file = str::lower(logFile.string()); if (str::endsWith(file, ".xml")) { - formatter.reset( - new logging::XMLFormatter("", "")); + formatter = std::make_unique("", ""); } else { - formatter.reset(new logging::StandardFormatter(logFormat)); + formatter = std::make_unique(logFormat); } // setup logging handler std::unique_ptr logHandler; - if (file.empty() || file == "console") + if (file.empty() || (file == "console") || (file == "-")) logHandler.reset(new logging::StreamHandler()); else { diff --git a/modules/c++/logging/source/StandardFormatter.cpp b/modules/c++/logging/source/StandardFormatter.cpp index 82eeac8e7..32e687c34 100644 --- a/modules/c++/logging/source/StandardFormatter.cpp +++ b/modules/c++/logging/source/StandardFormatter.cpp @@ -48,15 +48,14 @@ void StandardFormatter::format(const LogRecord* record, io::OutputStream& os) co // populate log long threadId = sys::getThreadID(); std::string format = mFmt; - str::replace(format, THREAD_ID, str::toString(threadId)); + str::replace(format, THREAD_ID, std::to_string(threadId)); str::replace(format, LOG_NAME, name); str::replace(format, LOG_LEVEL, record->getLevelName()); str::replace(format, TIMESTAMP, record->getTimeStamp()); if (record->getLineNum() >= 0) { str::replace(format, FILE_NAME, record->getFile()); - str::replace(format, LINE_NUM, - str::toString(record->getLineNum())); + str::replace(format, LINE_NUM, std::to_string(record->getLineNum())); } else { diff --git a/modules/c++/logging/source/XMLFormatter.cpp b/modules/c++/logging/source/XMLFormatter.cpp index b0bd450bf..c3f41b2f4 100644 --- a/modules/c++/logging/source/XMLFormatter.cpp +++ b/modules/c++/logging/source/XMLFormatter.cpp @@ -54,8 +54,8 @@ void logging::XMLFormatter::format(const logging::LogRecord* record, io::OutputS // conver record std::string name = (record->getName().empty()) ? ("DEFAULT") : record->getName(); - std::string line = str::toString(record->getLineNum()); - std::string threadID = str::toString(sys::getThreadID()); + const auto line = std::to_string(record->getLineNum()); + const auto threadID = std::to_string(sys::getThreadID()); // populate vector with record std::vector logRecord; diff --git a/modules/c++/logging/unittests/test_exception_logger.cpp b/modules/c++/logging/unittests/test_exception_logger.cpp index 57016a0de..6084f1d87 100644 --- a/modules/c++/logging/unittests/test_exception_logger.cpp +++ b/modules/c++/logging/unittests/test_exception_logger.cpp @@ -22,6 +22,7 @@ #include #include +#include #include "TestCase.h" @@ -102,7 +103,7 @@ TEST_CASE(testExceptionWithBacktrace) } catch (const except::Throwable& t) { - TEST_ASSERT_EQ(t.getBacktrace().size(), static_cast(0)); + TEST_ASSERT_EQ(std::ssize(t.getBacktrace()), 0); s = t.toString(); what = t.what(); } diff --git a/modules/c++/math.linear/include/math/linear/Eigenvalue.h b/modules/c++/math.linear/include/math/linear/Eigenvalue.h index 39edf699d..724e031d3 100644 --- a/modules/c++/math.linear/include/math/linear/Eigenvalue.h +++ b/modules/c++/math.linear/include/math/linear/Eigenvalue.h @@ -96,9 +96,7 @@ class Eigenvalue if (A.rows() != A.cols()) { throw except::Exception(Ctxt( - "Expected square matrix but got rows = " + - str::toString(A.rows()) + ", cols = " + - str::toString(A.cols()))); + "Expected square matrix but got rows = " + std::to_string(A.rows()) + ", cols = " + std::to_string(A.cols()))); } if (isSymmetric(A)) diff --git a/modules/c++/math.linear/unittests/test_Vector.cpp b/modules/c++/math.linear/unittests/test_Vector.cpp index 1a4df6d46..4e912b21d 100644 --- a/modules/c++/math.linear/unittests/test_Vector.cpp +++ b/modules/c++/math.linear/unittests/test_Vector.cpp @@ -1,3 +1,4 @@ +#include #include #include "TestCase.h" #include "math/linear/Vector.h" @@ -256,8 +257,8 @@ TEST_CASE(testOperatorMinusEquals) Vector v2(5, -5); v2 -= v1; - TEST_ASSERT_EQ(v1.size(), static_cast(5)); - TEST_ASSERT_EQ(v2.size(), static_cast(5)); + TEST_ASSERT_EQ(std::ssize(v1), 5); + TEST_ASSERT_EQ(std::ssize(v2), 5); for (int i = 0; i < 5; i++) TEST_ASSERT_EQ(v2[i], -18); for (int i = 0; i < 5; i++) @@ -347,9 +348,9 @@ TEST_CASE(testOperatorMinus) Vector v3(v2 - v1); // TODO: Test what happens if v1 & v2 are of different lengths. - TEST_ASSERT_EQ(v1.size(), static_cast(4)); - TEST_ASSERT_EQ(v2.size(), static_cast(4)); - TEST_ASSERT_EQ(v3.size(), static_cast(4)); + TEST_ASSERT_EQ(std::ssize(v1), 4); + TEST_ASSERT_EQ(std::ssize(v2), 4); + TEST_ASSERT_EQ(std::ssize(v3), 4); for (int i = 0; i < 4; i++) { diff --git a/modules/c++/math.poly/include/math/poly/Fit.h b/modules/c++/math.poly/include/math/poly/Fit.h index 0a3978fdb..3e54777bf 100644 --- a/modules/c++/math.poly/include/math/poly/Fit.h +++ b/modules/c++/math.poly/include/math/poly/Fit.h @@ -82,7 +82,7 @@ template OneD fit(const Vector_T& x, << sizeX << " points for an order-" << order << "fit)! You should really have at least (order+1) = " << (order+1) << " points for this to do what you expect."; - throw except::Exception(Ctxt(excSS.str())); + throw except::Exception(Ctxt(excSS)); } // Compute mean value @@ -206,7 +206,7 @@ inline math::poly::TwoD fit(const math::linear::Matrix2D& x, << x.size() << " points for a " << acols << "-coefficient fit)!" << " You should really have at least (orderX+1)*(orderY+1) = " << acols << " points for this to do what you expect."; - throw except::Exception(Ctxt(excSS.str())); + throw except::Exception(Ctxt(excSS)); } diff --git a/modules/c++/math.poly/include/math/poly/Fixed1D.h b/modules/c++/math.poly/include/math/poly/Fixed1D.h index 5f14c6fcd..03024de73 100644 --- a/modules/c++/math.poly/include/math/poly/Fixed1D.h +++ b/modules/c++/math.poly/include/math/poly/Fixed1D.h @@ -203,14 +203,14 @@ template class Fixed1D _T& operator [] (size_t i) { if (i > _Order) - throw except::IndexOutOfRangeException(Ctxt(FmtX("index [%d] is not in range [0..%d]", i, _Order))); + throw except::IndexOutOfRangeException(Ctxt(str::Format("index [%d] is not in range [0..%d]", i, _Order))); return mCoef[i]; } _T operator [] (size_t i) const { if (i > _Order) - throw except::IndexOutOfRangeException(Ctxt(FmtX("index [%d] is not in range [0..%d]", i, _Order))); + throw except::IndexOutOfRangeException(Ctxt(str::Format("index [%d] is not in range [0..%d]", i, _Order))); return mCoef[i]; diff --git a/modules/c++/math.poly/include/math/poly/OneD.hpp b/modules/c++/math.poly/include/math/poly/OneD.hpp index 67fb59b7b..9aa025354 100644 --- a/modules/c++/math.poly/include/math/poly/OneD.hpp +++ b/modules/c++/math.poly/include/math/poly/OneD.hpp @@ -178,10 +178,9 @@ OneD<_T>::operator [] (size_t i) } else { - std::stringstream str; - str << "index: " << i << " not within range [0..." - << mCoef.size() << ")"; - throw except::IndexOutOfRangeException(Ctxt(str.str())); + std::ostringstream str; + str << "index: " << i << " not within range [0..." << mCoef.size() << ")"; + throw except::IndexOutOfRangeException(Ctxt(str)); } } @@ -196,9 +195,9 @@ OneD<_T>::operator [] (size_t i) const } else { - std::stringstream str; + std::ostringstream str; str << "idx(" << i << ") not within range [0..." << mCoef.size() << ")"; - throw except::IndexOutOfRangeException(Ctxt(str.str())); + throw except::IndexOutOfRangeException(Ctxt(str)); } } diff --git a/modules/c++/math.poly/include/math/poly/TwoD.h b/modules/c++/math.poly/include/math/poly/TwoD.h index 05c8893f4..574d49c54 100644 --- a/modules/c++/math.poly/include/math/poly/TwoD.h +++ b/modules/c++/math.poly/include/math/poly/TwoD.h @@ -109,15 +109,10 @@ class TwoD void set(size_t i, const OneD<_T>& p) { if (i > orderX()) - throw except::Exception( - Ctxt("Index [" + str::toString(i) + - "] is out of bounds for orderX [" + - str::toString(orderX()) + "]")); + throw except::Exception(Ctxt("Index [" + std::to_string(i) + "] is out of bounds for orderX [" + std::to_string(orderX()) + "]")); else if (p.order() != orderY()) throw except::Exception( - Ctxt("OneD poly [" + str::toString(p.order()) + - "] is of the incorrect size for orderY [" + - str::toString(orderY()) + "]")); + Ctxt("OneD poly [" + std::to_string(p.order()) + "] is of the incorrect size for orderY [" + std::to_string(orderY()) + "]")); else mCoef[i] = p; } diff --git a/modules/c++/math.poly/include/math/poly/TwoD.hpp b/modules/c++/math.poly/include/math/poly/TwoD.hpp index 2a2627540..87d7f7217 100644 --- a/modules/c++/math.poly/include/math/poly/TwoD.hpp +++ b/modules/c++/math.poly/include/math/poly/TwoD.hpp @@ -187,11 +187,9 @@ TwoD<_T>::operator [] (size_t i) const } else { - std::stringstream str; - str << "index:" << i << " not within range [0..." - << mCoef.size() << ")"; - - throw except::IndexOutOfRangeException(Ctxt(str.str())); + std::ostringstream str; + str << "index:" << i << " not within range [0..." << mCoef.size() << ")"; + throw except::IndexOutOfRangeException(Ctxt(str)); } return ret; } @@ -206,10 +204,9 @@ TwoD<_T>::operator [] (size_t i) } else { - std::stringstream str; - str << "index: " << i << " not within range [0..." - << mCoef.size() << ")"; - throw except::IndexOutOfRangeException(Ctxt(str.str())); + std::ostringstream str; + str << "index: " << i << " not within range [0..." << mCoef.size() << ")"; + throw except::IndexOutOfRangeException(Ctxt(str)); } } diff --git a/modules/c++/math/include/math/ConvexHull.h b/modules/c++/math/include/math/ConvexHull.h index 787e23119..55849f9bc 100644 --- a/modules/c++/math/include/math/ConvexHull.h +++ b/modules/c++/math/include/math/ConvexHull.h @@ -97,8 +97,7 @@ class ConvexHull { throw except::Exception(Ctxt( "ConvexHull constructor error: must use at least 2 input " - "points but " + str::toString(rawPoints.size()) + - " were used")); + "points but " + std::to_string(rawPoints.size()) + " were used")); } // Enforce (at compile time) that T is a signed type diff --git a/modules/c++/math/source/Utilities.cpp b/modules/c++/math/source/Utilities.cpp index 7d4cbc73c..aa60b36fc 100644 --- a/modules/c++/math/source/Utilities.cpp +++ b/modules/c++/math/source/Utilities.cpp @@ -41,7 +41,7 @@ sys::Uint64_T nChooseK(size_t n, size_t k) if (n < k) { throw except::Exception(Ctxt("n Choose k undefined for n < k.\n" - "n: " + str::toString(n) + " k: " + str::toString(k))); + "n: " + std::to_string(n) + " k: " + std::to_string(k))); } // Algorithm to compute n Choose k without using factorials found here: diff --git a/modules/c++/mem/include/mem/BufferView.h b/modules/c++/mem/include/mem/BufferView.h index 02816c526..55997392b 100644 --- a/modules/c++/mem/include/mem/BufferView.h +++ b/modules/c++/mem/include/mem/BufferView.h @@ -70,7 +70,7 @@ struct BufferView oss << "BufferView::section() called with sectionSize: " << sectionSize << " when"; oss << " there were only " << size << " elements in the BufferView"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } BufferView newSection(data, sectionSize); diff --git a/modules/c++/mem/include/mem/ScratchMemory.hpp b/modules/c++/mem/include/mem/ScratchMemory.hpp index 45c6fcd26..7b22af835 100644 --- a/modules/c++/mem/include/mem/ScratchMemory.hpp +++ b/modules/c++/mem/include/mem/ScratchMemory.hpp @@ -52,7 +52,7 @@ inline void ScratchMemory::put(const std::string& key, { std::ostringstream oss; oss << "Scratch memory space was already reserved for " << key; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } mSegments.insert( iterSeg, diff --git a/modules/c++/mem/source/ScratchMemory.cpp b/modules/c++/mem/source/ScratchMemory.cpp index a3f162daa..4677b1da9 100644 --- a/modules/c++/mem/source/ScratchMemory.cpp +++ b/modules/c++/mem/source/ScratchMemory.cpp @@ -212,9 +212,8 @@ const ScratchMemory::Segment& ScratchMemory::lookupSegment( if (mBuffer.data == nullptr) { std::ostringstream oss; - oss << "Tried to get scratch memory for \"" << key - << "\" before running setup."; - throw except::Exception(Ctxt(oss.str())); + oss << "Tried to get scratch memory for \"" << key << "\" before running setup."; + throw except::Exception(Ctxt(oss)); } std::map::const_iterator iterSeg = mSegments.find(key); @@ -222,7 +221,7 @@ const ScratchMemory::Segment& ScratchMemory::lookupSegment( { std::ostringstream oss; oss << "Scratch memory segment was not found for \"" << key << "\""; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } const Segment& segment = iterSeg->second; @@ -230,9 +229,8 @@ const ScratchMemory::Segment& ScratchMemory::lookupSegment( { std::ostringstream oss; oss << "Trying to get buffer index " << indexBuffer << " for \"" - << key << "\", which has only " << segment.buffers.size() - << " buffers"; - throw except::Exception(Ctxt(oss.str())); + << key << "\", which has only " << segment.buffers.size() << " buffers"; + throw except::Exception(Ctxt(oss)); } return segment; } diff --git a/modules/c++/mt/include/mt/Algorithm.h b/modules/c++/mt/include/mt/Algorithm.h index ba17f39f5..83041d8c2 100644 --- a/modules/c++/mt/include/mt/Algorithm.h +++ b/modules/c++/mt/include/mt/Algorithm.h @@ -20,22 +20,80 @@ * */ -#ifndef CODA_OSS_mt_Algorithm_h_INCLUDED_ -#define CODA_OSS_mt_Algorithm_h_INCLUDED_ #pragma once #include #include #include +#include "config/compiler_extensions.h" +#include "coda_oss/CPlusPlus.h" +#if CODA_OSS_cpp17 + // is broken with the older version of GCC we're using + #if (__GNUC__ >= 10) || _MSC_VER + #include + #define CODA_OSS_mt_Algorithm_has_execution 1 + #endif +#endif + namespace mt { -// There was a transform_async() utility here, but I removed it. -// -// First of all, C++11's std::async() is now (in 2023) thought of as maybe a -// bit "half baked," and perhaps shouldn't be emulated. Then, C++17 added -// parallel algorithms which might be a better ... although we're still at C++14. -} +// "Roll our own" `std::transform(execution::par)` using std::async() +// https://en.cppreference.com/w/cpp/algorithm/transform + +// Our own `Transform_par_()` is built on `std::async()`; for that we need to control +// a couple of settings. +struct Transform_par_settings final +{ + Transform_par_settings() = default; + + Transform_par_settings(ptrdiff_t cutoff) : cutoff_(cutoff) { } + Transform_par_settings(std::launch policy) : policy_(policy) { } + Transform_par_settings(ptrdiff_t cutoff, std::launch policy) : cutoff_(cutoff), policy_(policy) { } + Transform_par_settings(std::launch policy, ptrdiff_t cutoff) : Transform_par_settings(cutoff, policy) { } + + // The value of "default_cutoff" was determined by testing; there is nothing + // special about it, feel free to change it. + static constexpr ptrdiff_t dimension = 128 * 8; + static constexpr ptrdiff_t default_cutoff = dimension * dimension; + ptrdiff_t cutoff_ = default_cutoff; -#endif // CODA_OSS_mt_Algorithm_h_INCLUDED_ + // https://en.cppreference.com/w/cpp/thread/launch + std::launch policy_ = std::launch::async; // "the task is executed on a different thread, potentially by creating and launching it first" +}; +template +inline OutputIt Transform_par_(InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op, + const Transform_par_settings& settings) +{ + // https://en.cppreference.com/w/cpp/thread/async + const auto len = std::distance(first1, last1); + if (len < settings.cutoff_) + { + return std::transform(first1, last1, d_first, unary_op); + } + + const auto mid1 = first1 + len / 2; + const auto d_mid = d_first + len / 2; + auto handle = std::async(settings.policy_, Transform_par_, mid1, last1, d_mid, unary_op, settings); + Transform_par_(first1, mid1, d_first, unary_op, settings); + return handle.get(); +} +template +inline OutputIt Transform_par(InputIt first1, InputIt last1, OutputIt d_first, UnaryOperation unary_op, + Transform_par_settings settings = Transform_par_settings{}) +{ +#if CODA_OSS_mt_Algorithm_has_execution + #if __GNUC__ + // std::execution::par is dramatically slower w/GCC than using our own ... ??? + return Transform_par_(first1, last1, d_first, unary_op, settings); // TODO: std::execution::par + #else + CODA_OSS_mark_symbol_unused(settings); + return std::transform(std::execution::par, first1, last1, d_first, unary_op); + #endif // __GNUC__ +#else + return Transform_par_(first1, last1, d_first, unary_op, settings); +#endif // CODA_OSS_mt_Algorithm_has_execution +} + +} diff --git a/modules/c++/mt/include/mt/BalancedRunnable1D.h b/modules/c++/mt/include/mt/BalancedRunnable1D.h index c7af782fb..3ee200e04 100644 --- a/modules/c++/mt/include/mt/BalancedRunnable1D.h +++ b/modules/c++/mt/include/mt/BalancedRunnable1D.h @@ -159,7 +159,7 @@ void runBalanced1D(size_t numElements, std::ostringstream ostr; ostr << "Got " << numThreads << " threads but " << ops.size() << " functors"; - throw except::Exception(Ctxt(ostr.str())); + throw except::Exception(Ctxt(ostr)); } if (numThreads <= 1) diff --git a/modules/c++/mt/include/mt/CPUAffinityInitializerLinux.h b/modules/c++/mt/include/mt/CPUAffinityInitializerLinux.h index cde51eb61..494f6fb5e 100644 --- a/modules/c++/mt/include/mt/CPUAffinityInitializerLinux.h +++ b/modules/c++/mt/include/mt/CPUAffinityInitializerLinux.h @@ -40,6 +40,7 @@ namespace mt struct AbstractNextCPUProviderLinux { virtual std::unique_ptr nextCPU() = 0; + virtual ~AbstractNextCPUProviderLinux() {} }; /*! diff --git a/modules/c++/mt/include/mt/Runnable1D.h b/modules/c++/mt/include/mt/Runnable1D.h index dbcde3aad..fb277b1e8 100644 --- a/modules/c++/mt/include/mt/Runnable1D.h +++ b/modules/c++/mt/include/mt/Runnable1D.h @@ -75,7 +75,7 @@ void run1D(size_t numElements, size_t numThreads, const std::vector& ops) std::ostringstream ostr; ostr << "Got " << numThreads << " threads but " << ops.size() << " functors"; - throw except::Exception(Ctxt(ostr.str())); + throw except::Exception(Ctxt(ostr)); } if (numThreads <= 1) diff --git a/modules/c++/mt/include/mt/WorkSharingBalancedRunnable1D.h b/modules/c++/mt/include/mt/WorkSharingBalancedRunnable1D.h index dd8e4553d..95f36e6a7 100644 --- a/modules/c++/mt/include/mt/WorkSharingBalancedRunnable1D.h +++ b/modules/c++/mt/include/mt/WorkSharingBalancedRunnable1D.h @@ -238,7 +238,7 @@ void runWorkSharingBalanced1D(size_t numElements, std::ostringstream ostr; ostr << "Got " << numThreads << " threads but " << ops.size() << " functors"; - throw except::Exception(Ctxt(ostr.str())); + throw except::Exception(Ctxt(ostr)); } std::vector threadPoolEndElements; diff --git a/modules/c++/mt/include/mt/WorkerThread.h b/modules/c++/mt/include/mt/WorkerThread.h index 2a2e20468..d2321e549 100644 --- a/modules/c++/mt/include/mt/WorkerThread.h +++ b/modules/c++/mt/include/mt/WorkerThread.h @@ -98,7 +98,7 @@ template class WorkerThread : public sys::Thread */ std::string getThreadId() { - return str::toString(sys::getThreadID()); + return std::to_string(sys::getThreadID()); } protected: diff --git a/modules/c++/mt/source/CPUAffinityInitializerLinux.cpp b/modules/c++/mt/source/CPUAffinityInitializerLinux.cpp index 01181be6b..2f728fad9 100644 --- a/modules/c++/mt/source/CPUAffinityInitializerLinux.cpp +++ b/modules/c++/mt/source/CPUAffinityInitializerLinux.cpp @@ -51,14 +51,14 @@ std::vector mergeAvailableCPUs() namespace mt { -class AvailableCPUProvider : public AbstractNextCPUProviderLinux +struct AvailableCPUProvider final : public AbstractNextCPUProviderLinux { -public: AvailableCPUProvider() : mCPUs(mergeAvailableCPUs()), mNextCPUIndex(0) { } + ~AvailableCPUProvider() = default; virtual std::unique_ptr nextCPU() override { @@ -66,7 +66,7 @@ class AvailableCPUProvider : public AbstractNextCPUProviderLinux { std::ostringstream msg; msg << "No more CPUs available (size = " << mCPUs.size() << ")"; - throw except::Exception(Ctxt(msg.str())); + throw except::Exception(Ctxt(msg)); } std::unique_ptr mask(new sys::ScopedCPUMaskUnix()); @@ -79,13 +79,13 @@ class AvailableCPUProvider : public AbstractNextCPUProviderLinux size_t mNextCPUIndex; }; -class OffsetCPUProvider : public AbstractNextCPUProviderLinux +struct OffsetCPUProvider final : public AbstractNextCPUProviderLinux { -public: OffsetCPUProvider(int initialOffset) : mNextCPU(initialOffset) { } + ~OffsetCPUProvider() = default; virtual std::unique_ptr nextCPU() override { diff --git a/modules/c++/mt/tests/MTSingletonTest.cpp b/modules/c++/mt/tests/MTSingletonTest.cpp index beb1719e3..e71dce345 100644 --- a/modules/c++/mt/tests/MTSingletonTest.cpp +++ b/modules/c++/mt/tests/MTSingletonTest.cpp @@ -103,7 +103,7 @@ class Thespian : public Runnable } void run() override { - //__debugln__(FmtX("[%s]:", mName.c_str())); + //__debugln__(str::Format("[%s]:", mName.c_str())); doLines(); } virtual void doLines() = 0; diff --git a/modules/c++/mt/unittests/test_mt_byte_swap.cpp b/modules/c++/mt/unittests/test_mt_byte_swap.cpp index d2099cf83..ccc2e92cc 100644 --- a/modules/c++/mt/unittests/test_mt_byte_swap.cpp +++ b/modules/c++/mt/unittests/test_mt_byte_swap.cpp @@ -28,14 +28,20 @@ #include // std::byte #include +#include + #include +#include + +#undef min +#undef max -static std::vector make_origValues(size_t NUM_PIXELS) +static std::vector make_origValues_(size_t count) { ::srand(334); - std::vector retval(NUM_PIXELS); - for (size_t ii = 0; ii < NUM_PIXELS; ++ii) + std::vector retval(count); + for (size_t ii = 0; ii < count; ++ii) { const auto value = static_cast(::rand()) / RAND_MAX * std::numeric_limits::max(); @@ -44,10 +50,16 @@ static std::vector make_origValues(size_t NUM_PIXELS) return retval; } +static constexpr size_t NUM_PIXELS = 10000; +static const std::vector& make_origValues() +{ + static const auto retval = make_origValues_(NUM_PIXELS); + return retval; +} + TEST_CASE(testThreadedByteSwap) { - constexpr size_t NUM_PIXELS = 10000; - const auto origValues = make_origValues(NUM_PIXELS); + const auto& origValues = make_origValues(); constexpr size_t numThreads = 4; @@ -59,14 +71,70 @@ TEST_CASE(testThreadedByteSwap) std::vector swappedValues2(origValues.size()); mt::threadedByteSwap(origValues.data(), sizeof(origValues[0]), NUM_PIXELS, numThreads, swappedValues2.data()); - // Everything should match - for (size_t ii = 0; ii < NUM_PIXELS; ++ii) + for (size_t ii = 0; ii < NUM_PIXELS; ++ii) // Everything should match { TEST_ASSERT_EQ(values1[ii], swappedValues2[ii]); } } +TEST_CASE(test_transform_ByteSwap) +{ + const auto& origValues = make_origValues(); + + // Byte swap the old-fashioned way + constexpr size_t numThreads = 4; + auto expected_(origValues); + constexpr auto elemSize = sizeof(expected_[0]); + mt::threadedByteSwap(expected_.data(), elemSize, NUM_PIXELS, numThreads); + const auto& expected = expected_; + + // Byte swap into output buffer + const auto byteSwap = [&](const auto& buffer_) { + auto buffer = buffer_; + sys::byteSwap(&buffer, elemSize, 1 /*numElements*/); + return buffer; + }; + + std::vector actual(origValues.size()); + std::transform(origValues.begin(), origValues.end(), actual.begin(), byteSwap); + for (size_t ii = 0; ii < NUM_PIXELS; ++ii) // Everything should match + { + TEST_ASSERT_EQ(expected[ii], actual[ii]); + } +} + +TEST_CASE(test_Transform_par_ByteSwap) +{ + const auto& origValues = make_origValues(); + + // Byte swap the old-fashioned way + constexpr size_t numThreads = 4; + auto expected_(origValues); + constexpr auto elemSize = sizeof(expected_[0]); + mt::threadedByteSwap(expected_.data(), elemSize, NUM_PIXELS, numThreads); + const auto& expected = expected_; + + // Byte swap into output buffer + const auto byteSwap = [&](const auto& buffer_) { + auto buffer = buffer_; + sys::byteSwap(&buffer, elemSize, 1 /*numElements*/); + return buffer; + }; + + // be sure we do something more than just call std::transform() + const mt::Transform_par_settings settings{ NUM_PIXELS / 4 /*cutoff*/ }; + + std::vector actual(origValues.size()); + mt::Transform_par(origValues.begin(), origValues.end(), actual.begin(), byteSwap, settings); + for (size_t ii = 0; ii < NUM_PIXELS; ++ii) // Everything should match + { + TEST_ASSERT_EQ(expected[ii], actual[ii]); + } +} + TEST_MAIN( TEST_CHECK(testThreadedByteSwap); + TEST_CHECK(test_transform_ByteSwap); + TEST_CHECK(test_Transform_par_ByteSwap); ) \ No newline at end of file diff --git a/modules/c++/net.ssl/source/SSLConnection.cpp b/modules/c++/net.ssl/source/SSLConnection.cpp index 903fa077d..433d73748 100644 --- a/modules/c++/net.ssl/source/SSLConnection.cpp +++ b/modules/c++/net.ssl/source/SSLConnection.cpp @@ -37,7 +37,7 @@ net::ssl::SSLConnection::SSLConnection(std::unique_ptr&& socket, mSSL = SSL_new(ctx); if (mSSL == nullptr) { - throw net::ssl::SSLException(Ctxt(FmtX("SSL_new failed"))); + throw net::ssl::SSLException(Ctxt(str::Format("SSL_new failed"))); } setupSocket(host); @@ -87,7 +87,7 @@ void net::ssl::SSLConnection::setupSocket(const std::string& hostName) #endif throw net::ssl::SSLException - (Ctxt(FmtX("SSL_connect failed: %d", SSL_get_error(mSSL, val)))); + (Ctxt(str::Format("SSL_connect failed: %d", SSL_get_error(mSSL, val)))); } if(mServerAuthentication) @@ -143,7 +143,7 @@ sys::SSize_T net::ssl::SSLConnection::read(sys::byte* b, sys::Size_T len) std::cout << "=============================================" << std::endl << std::endl; #endif - throw net::ssl::SSLException(Ctxt(FmtX("When receiving %d bytes", + throw net::ssl::SSLException(Ctxt(str::Format("When receiving %d bytes", len)) ); } else if (numBytes == 0) @@ -155,7 +155,7 @@ sys::SSize_T net::ssl::SSLConnection::read(sys::byte* b, sys::Size_T len) return -1; } #if defined(__DEBUG_SOCKET) - std::cout << FmtX("Read %d bytes from socket:", numBytes) << std::endl; + std::cout << str::Format("Read %d bytes from socket:", numBytes) << std::endl; std::cout << "---------------------------------------------" << std::endl; std::cout << std::string(b, numBytes) << std::endl; std::cout << "---------------------------------------------" << std::endl; @@ -172,7 +172,7 @@ void net::ssl::SSLConnection::write(const sys::byte* b, sys::Size_T len) const auto numBytes = SSL_write(mSSL, (const char*)b, len); if (static_cast(numBytes) != len) { - throw net::ssl::SSLException(Ctxt(FmtX("Tried sending %d bytes, %d sent", + throw net::ssl::SSLException(Ctxt(str::Format("Tried sending %d bytes, %d sent", len, numBytes)) ); } diff --git a/modules/c++/net.ssl/source/SSLConnectionClientFactory.cpp b/modules/c++/net.ssl/source/SSLConnectionClientFactory.cpp index 5a9d44148..63a721a81 100644 --- a/modules/c++/net.ssl/source/SSLConnectionClientFactory.cpp +++ b/modules/c++/net.ssl/source/SSLConnectionClientFactory.cpp @@ -60,12 +60,12 @@ void net::ssl::SSLConnectionClientFactory::initializeContext() if(method == nullptr) { - throw net::ssl::SSLException(Ctxt(FmtX("SSLv23_client_method failed"))); + throw net::ssl::SSLException(Ctxt(str::Format("SSLv23_client_method failed"))); } mCtx = SSL_CTX_new(method); if(mCtx == nullptr) { - throw net::ssl::SSLException(Ctxt(FmtX("SSL_CTX_new failed"))); + throw net::ssl::SSLException(Ctxt(str::Format("SSL_CTX_new failed"))); } if(mClientAuthentication) diff --git a/modules/c++/net.ssl/tests/SSLTestClient.cpp b/modules/c++/net.ssl/tests/SSLTestClient.cpp index 074b4abb2..ff8db2b6f 100644 --- a/modules/c++/net.ssl/tests/SSLTestClient.cpp +++ b/modules/c++/net.ssl/tests/SSLTestClient.cpp @@ -39,7 +39,7 @@ int main(int argc, char **argv) try { if (argc != 2) - throw Exception(FmtX("Usage: %s ", argv[0])); + throw Exception(str::Format("Usage: %s ", argv[0])); URL url(argv[1]); //int sslOn = atoi(argv[2]); diff --git a/modules/c++/net.ssl/tests/SSLTestClientNoURL.cpp b/modules/c++/net.ssl/tests/SSLTestClientNoURL.cpp index 60baa34fa..89c4d6476 100644 --- a/modules/c++/net.ssl/tests/SSLTestClientNoURL.cpp +++ b/modules/c++/net.ssl/tests/SSLTestClientNoURL.cpp @@ -40,7 +40,7 @@ int main(int argc, char** argv) try { if (argc != 3) - throw Exception(FmtX("Usage: %s ", argv[0])); + throw Exception(str::Format("Usage: %s ", argv[0])); std::string host(argv[1]); int port(atoi(argv[2])); diff --git a/modules/c++/net/include/net/Socket.h b/modules/c++/net/include/net/Socket.h index 7d75eae46..024af735c 100644 --- a/modules/c++/net/include/net/Socket.h +++ b/modules/c++/net/include/net/Socket.h @@ -170,7 +170,7 @@ class Socket std::ostringstream oss; oss << "Socket setOptions failure: " << err.toString(); - throw sys::SocketException(Ctxt(oss.str())); + throw sys::SocketException(Ctxt(oss)); } } diff --git a/modules/c++/net/source/DaemonUnix.cpp b/modules/c++/net/source/DaemonUnix.cpp index 8683816f9..af0a1e0bf 100644 --- a/modules/c++/net/source/DaemonUnix.cpp +++ b/modules/c++/net/source/DaemonUnix.cpp @@ -258,12 +258,12 @@ void DaemonUnix::redirectStreamsTo(const std::string& filename) if (openFileFor(STDOUT_FILENO, filename, O_WRONLY|O_CREAT|O_TRUNC) < 0) { throw except::Exception( - Ctxt(FmtX("Failed to open file %s for STDOUT.", filename.c_str()))); + Ctxt(str::Format("Failed to open file %s for STDOUT.", filename))); } if (openFileFor(STDERR_FILENO, filename, O_WRONLY|O_CREAT|O_TRUNC) < 0) { throw except::Exception( - Ctxt(FmtX("Failed to open file %s for STDERR.", filename.c_str()))); + Ctxt(str::Format("Failed to open file %s for STDERR.", filename))); } } diff --git a/modules/c++/net/source/Socket.cpp b/modules/c++/net/source/Socket.cpp index 9c0c791b9..33c44057d 100644 --- a/modules/c++/net/source/Socket.cpp +++ b/modules/c++/net/source/Socket.cpp @@ -101,10 +101,8 @@ size_t net::Socket::recv(void* b, size_t len, int flags) sys::Err err; std::ostringstream oss; - oss << "When receiving " << str::toString(len) << " bytes: " << - err.toString(); - - throw sys::SocketException(Ctxt(oss.str())); + oss << "When receiving " << len << " bytes: " << err.toString(); + throw sys::SocketException(Ctxt(oss)); } else if (numBytes == 0) { @@ -115,7 +113,7 @@ size_t net::Socket::recv(void* b, size_t len, int flags) return static_cast(-1); } #if defined(__DEBUG_SOCKET) - std::cout << FmtX("Read %d bytes from socket:", numBytes) << std::endl; + std::cout << str::Format("Read %d bytes from socket:", numBytes) << std::endl; std::cout << "---------------------------------------------" << std::endl; std::cout << std::string(b, numBytes) << std::endl; std::cout << "---------------------------------------------" << std::endl; @@ -170,7 +168,7 @@ void net::Socket::send(const void* b, size_t len, int flags) oss << "Tried sending " << len << " bytes, " << numBytes << " sent: " << err.toString(); - throw sys::SocketException(Ctxt(oss.str())); + throw sys::SocketException(Ctxt(oss)); } } @@ -193,6 +191,6 @@ void net::Socket::sendTo(const SocketAddress& address, oss << "Tried sending " << len << " bytes, " << numBytes << " sent: " << err.toString(); - throw sys::SocketException(Ctxt(oss.str())); + throw sys::SocketException(Ctxt(oss)); } } diff --git a/modules/c++/net/tests/NetConnectionClientTest.cpp b/modules/c++/net/tests/NetConnectionClientTest.cpp index 992ac5eca..abe0b3579 100644 --- a/modules/c++/net/tests/NetConnectionClientTest.cpp +++ b/modules/c++/net/tests/NetConnectionClientTest.cpp @@ -39,7 +39,7 @@ int main(int argc, char **argv) try { if (argc != 3) - throw Exception(FmtX("Usage: %s ", argv[0])); + throw Exception(str::Format("Usage: %s ", argv[0])); std::string host(argv[1]); int port(atoi(argv[2])); diff --git a/modules/c++/net/tests/NetConnectionServerTest.cpp b/modules/c++/net/tests/NetConnectionServerTest.cpp index ed72a907b..0cb8cdb0c 100644 --- a/modules/c++/net/tests/NetConnectionServerTest.cpp +++ b/modules/c++/net/tests/NetConnectionServerTest.cpp @@ -74,7 +74,7 @@ int main(int argc, char **argv) try { if (argc < 2) - throw Exception(FmtX("Usage: %s (-mt|-st|-tp)", argv[0])); + throw Exception(str::Format("Usage: %s (-mt|-st|-tp)", argv[0])); net::AllocStrategy* strategy = nullptr; diff --git a/modules/c++/net/tests/SerializableTestClient.cpp b/modules/c++/net/tests/SerializableTestClient.cpp index 229758ca3..0c472bf09 100644 --- a/modules/c++/net/tests/SerializableTestClient.cpp +++ b/modules/c++/net/tests/SerializableTestClient.cpp @@ -39,7 +39,7 @@ int main(int argc, char **argv) try { if (argc != 2) - throw Exception(FmtX("Usage: %s ", argv[0])); + throw Exception(str::Format("Usage: %s ", argv[0])); URL url(argv[1]); diff --git a/modules/c++/net/tests/URLTest.cpp b/modules/c++/net/tests/URLTest.cpp index aacde069c..e6c5f7932 100644 --- a/modules/c++/net/tests/URLTest.cpp +++ b/modules/c++/net/tests/URLTest.cpp @@ -36,7 +36,7 @@ int main(int argc, char **argv) try { if (argc != 2) - throw Exception(FmtX("Usage: %s ", argv[0])); + throw Exception(str::Format("Usage: %s ", argv[0])); URL url(argv[1]); diff --git a/modules/c++/pch.h b/modules/c++/pch.h index 7952e6efa..5cda65986 100644 --- a/modules/c++/pch.h +++ b/modules/c++/pch.h @@ -5,8 +5,13 @@ // Do not add files here that you will be updating frequently as this negates the performance advantage. #pragma once -#ifndef CODA_OSS_pch_h_INCLUDED_ -#define CODA_OSS_pch_h_INCLUDED_ + +// We're building in Visual Studio ... used to control where we get a little bit +// of config info +#define CODA_OSS_PCH 1 +#ifndef CODA_OSS_LIBRARY_SHARED +#define CODA_OSS_LIBRARY_SHARED 1 +#endif #include "coda_oss/CPlusPlus.h" #include "config/disable_compiler_warnings.h" @@ -114,4 +119,3 @@ CODA_OSS_disable_warning_pop #include "hdf5/lite/H5_.h" #pragma comment(lib, "hdf5-c++.lib") -#endif //CODA_OSS_pch_h_INCLUDED_ diff --git a/modules/c++/plugin/include/plugin/BasicPluginManager.h b/modules/c++/plugin/include/plugin/BasicPluginManager.h index 738dabe94..6e65ea9eb 100644 --- a/modules/c++/plugin/include/plugin/BasicPluginManager.h +++ b/modules/c++/plugin/include/plugin/BasicPluginManager.h @@ -278,12 +278,9 @@ template class BasicPluginManager for (unsigned int i = 0; ops[i] != nullptr; i++) oss << ops[i] << ":"; - eh->onPluginVersionUnsupported( - str::Format("For plugin supporting ops %s version [%d.%d] not supported (%d.%d)", - oss.str().c_str(), majorVersion, minorVersion, - mMajorVersion, mMinorVersion - ) - ); + auto unsupported = str::Format("For plugin supporting ops %s version ", oss.str()); + unsupported += str::Format("[%d.%d] not supported (%d.%d)", majorVersion, minorVersion, mMajorVersion, mMinorVersion); + eh->onPluginVersionUnsupported(unsupported); return; } @@ -293,7 +290,7 @@ template class BasicPluginManager if (! pluginHandler ) { eh->onPluginLoadFailed( - FmtX("Failed to spawn handler for op %s", ops[i])); + str::Format("Failed to spawn handler for op %s", ops[i])); // Keep going } mHandlers[ops[i]].first = pluginHandler; diff --git a/modules/c++/plugin/include/plugin/ErrorHandler.h b/modules/c++/plugin/include/plugin/ErrorHandler.h index be7ca3c8a..248b61f46 100644 --- a/modules/c++/plugin/include/plugin/ErrorHandler.h +++ b/modules/c++/plugin/include/plugin/ErrorHandler.h @@ -19,7 +19,7 @@ * see . * */ - +#pragma once #ifndef __PLUGIN_ERROR_HANDLER_H__ #define __PLUGIN_ERROR_HANDLER_H__ @@ -27,9 +27,11 @@ #include #include +#include "config/Exports.h" + namespace plugin { -class ErrorHandler +class CODA_OSS_API ErrorHandler { public: ErrorHandler() {} @@ -47,7 +49,7 @@ class ErrorHandler virtual void onPluginError(except::Context& c) = 0; }; -class DefaultErrorHandler : public ErrorHandler +class CODA_OSS_API DefaultErrorHandler : public ErrorHandler { public: DefaultErrorHandler(logging::LoggerPtr logger = logging::LoggerPtr()); diff --git a/modules/c++/polygon/source/PolygonMask.cpp b/modules/c++/polygon/source/PolygonMask.cpp index d9a729fef..6ad904aa2 100644 --- a/modules/c++/polygon/source/PolygonMask.cpp +++ b/modules/c++/polygon/source/PolygonMask.cpp @@ -134,9 +134,8 @@ PolygonMask::PolygonMask(const std::vector >& points, // happen. std::ostringstream ostr; ostr << "Requires a convex polygon but these points produced " - << intersectionsVec.size() << " intersections for row " - << row; - throw except::Exception(Ctxt(ostr.str())); + << intersectionsVec.size() << " intersections for row " << row; + throw except::Exception(Ctxt(ostr)); } } diff --git a/modules/c++/re/source/RegexPCRE.cpp b/modules/c++/re/source/RegexPCRE.cpp index d70885e3e..01b0393b3 100644 --- a/modules/c++/re/source/RegexPCRE.cpp +++ b/modules/c++/re/source/RegexPCRE.cpp @@ -137,7 +137,7 @@ class ScopedMatchData ostr << "Match: Match substring out of range (" << index << ", " << end << ") for string of length " << str.length(); - throw re::RegexException(Ctxt(ostr.str())); + throw re::RegexException(Ctxt(ostr)); } const size_t subStringLength = end - index; @@ -225,7 +225,7 @@ Regex& Regex::compile(const std::string& pattern) std::ostringstream ostr; ostr << "PCRE compilation failed at offset " << errorOffset << ": " << getErrorMessage(errorCode); - throw RegexException(Ctxt(ostr.str())); + throw RegexException(Ctxt(ostr)); } return *this; @@ -330,6 +330,19 @@ void Regex::split(const std::string& str, std::vector& v) } } +inline static void replace(std::string& result, size_t pos, size_t count, const std::string& str) +{ + // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 + #if _WIN32 && __SANITIZE_ADDRESS__ && (_MSC_VER <= 1933 /*VS 2022 17.3*/) + // ASAN diagnostic on Windows with replace() ... bug in VS? + const auto input = result; + result = input.substr(0, pos); + result += str; + result += input.substr(pos + count); + #else + result.replace(pos, count, str); + #endif +} std::string Regex::sub(const std::string& str, const std::string& repl) { size_t begin; @@ -339,7 +352,7 @@ std::string Regex::sub(const std::string& str, const std::string& repl) std::string result = search(str, startIndex, 0, begin, end); while (!result.empty()) { - toReplace.replace(begin, result.size(), repl); + replace(toReplace, begin, result.size(), repl); // You can't skip ahead result.size() here because 'repl' may be shorter // than 'result' diff --git a/modules/c++/sio.lite/include/sio/lite/FileHeader.h b/modules/c++/sio.lite/include/sio/lite/FileHeader.h index a5633e509..1a76c1676 100644 --- a/modules/c++/sio.lite/include/sio/lite/FileHeader.h +++ b/modules/c++/sio.lite/include/sio/lite/FileHeader.h @@ -19,6 +19,7 @@ * see . * */ +#pragma once #ifndef __SIO_LITE_FILE_HEADER_H__ #define __SIO_LITE_FILE_HEADER_H__ @@ -28,6 +29,7 @@ #include #include #include +#include "config/Exports.h" #include "sio/lite/UserDataDictionary.h" #include "sio/lite/InvalidHeaderException.h" #include "sio/lite/UnsupportedDataTypeException.h" @@ -37,7 +39,7 @@ namespace sio namespace lite { -class FileHeader +class CODA_OSS_API FileHeader { public: /** Unsigned byte data */ diff --git a/modules/c++/sio.lite/include/sio/lite/FileReader.h b/modules/c++/sio.lite/include/sio/lite/FileReader.h index b94fbc1ae..885b3b68b 100644 --- a/modules/c++/sio.lite/include/sio/lite/FileReader.h +++ b/modules/c++/sio.lite/include/sio/lite/FileReader.h @@ -19,10 +19,6 @@ * see . * */ -#ifndef CODA_OSS_sio_lite_FileReader_h_INCLUDED_ -#define CODA_OSS_sio_lite_FileReader_h_INCLUDED_ #pragma once - #include "sio/lite/SioFileReader.h" -#endif // CODA_OSS_sio_lite_FileReader_h_INCLUDED_ diff --git a/modules/c++/sio.lite/include/sio/lite/SioFileReader.h b/modules/c++/sio.lite/include/sio/lite/SioFileReader.h index 446476dfc..54fe31c32 100644 --- a/modules/c++/sio.lite/include/sio/lite/SioFileReader.h +++ b/modules/c++/sio.lite/include/sio/lite/SioFileReader.h @@ -19,12 +19,14 @@ * see . * */ +#pragma once #ifndef __SIO_LITE_FILE_READER_H__ #define __SIO_LITE_FILE_READER_H__ #include #include #include +#include "config/Exports.h" #include "sio/lite/InvalidHeaderException.h" #include "sio/lite/StreamReader.h" @@ -80,12 +82,9 @@ namespace lite \endcode */ -class FileReader : public StreamReader, public io::Seekable +class CODA_OSS_API FileReader : public StreamReader, public io::Seekable { - - public: - /** Constructor */ FileReader() : StreamReader() {} diff --git a/modules/c++/sio.lite/include/sio/lite/SioFileWriter.h b/modules/c++/sio.lite/include/sio/lite/SioFileWriter.h index 8d75266d5..72a895b00 100644 --- a/modules/c++/sio.lite/include/sio/lite/SioFileWriter.h +++ b/modules/c++/sio.lite/include/sio/lite/SioFileWriter.h @@ -173,7 +173,7 @@ template void writeSIO(const T* image, size_t rows, size_t cols, et = FileHeader::UNSIGNED; break; default: - throw except::Exception(Ctxt(FmtX("Unexpected es: %d", es))); + throw except::Exception(Ctxt(str::Format("Unexpected es: %d", es))); } } diff --git a/modules/c++/sio.lite/include/sio/lite/StreamReader.h b/modules/c++/sio.lite/include/sio/lite/StreamReader.h index 982b8900f..efa9897ff 100644 --- a/modules/c++/sio.lite/include/sio/lite/StreamReader.h +++ b/modules/c++/sio.lite/include/sio/lite/StreamReader.h @@ -19,10 +19,12 @@ * see . * */ +#pragma once #ifndef __SIO_LITE_STREAM_READER_H__ #define __SIO_LITE_STREAM_READER_H__ #include +#include "config/Exports.h" #include "sio/lite/FileHeader.h" namespace sio @@ -87,7 +89,7 @@ namespace lite \endcode * */ -class StreamReader : public io::InputStream +class CODA_OSS_API StreamReader : public io::InputStream { public: /** Constructor */ diff --git a/modules/c++/sio.lite/include/sio/lite/UserDataDictionary.h b/modules/c++/sio.lite/include/sio/lite/UserDataDictionary.h index 627c975f8..00aae905b 100644 --- a/modules/c++/sio.lite/include/sio/lite/UserDataDictionary.h +++ b/modules/c++/sio.lite/include/sio/lite/UserDataDictionary.h @@ -77,6 +77,7 @@ class OrderedDictionary } virtual size_t size() const { return mList.size(); } + virtual bool empty() const { return mList.empty(); } virtual void add(Key_T key, const Value_T& value) { diff --git a/modules/c++/sio.lite/source/FileHeader.cpp b/modules/c++/sio.lite/source/FileHeader.cpp index 8a7c8a40f..619f8af72 100644 --- a/modules/c++/sio.lite/source/FileHeader.cpp +++ b/modules/c++/sio.lite/source/FileHeader.cpp @@ -65,7 +65,7 @@ long sio::lite::FileHeader::getLength() const { size_t length = SIO_HEADER_LENGTH; - if (userData.size() > 0) + if (!userData.empty()) length += 4; //num fields int for (sio::lite::UserDataDictionary::ConstIterator it = userData.begin(); it != userData.end(); ++it) @@ -158,7 +158,7 @@ void sio::lite::FileHeader::to(size_t numBands, io::OutputStream& os) void sio::lite::FileHeader::writeUserData(io::OutputStream& os) { - const auto numFields = static_cast(userData.size()); + const auto numFields = gsl::narrow(userData.size()); os.write((const sys::byte*)&numFields, 4); for(sio::lite::UserDataDictionary::Iterator it = userData.begin(); @@ -171,7 +171,7 @@ void sio::lite::FileHeader::writeUserData(io::OutputStream& os) os.write((const sys::byte*)key.c_str(), keySize); std::vector& uData = it->second; - const auto udSize = static_cast(uData.size()); + const auto udSize = gsl::narrow(uData.size()); os.write((const sys::byte*)&udSize, 4); //Do we need to check for endian-ness and possibly byteswap??? diff --git a/modules/c++/std/include/import/std.h b/modules/c++/std/include/import/std.h index 32702da30..5c41ee61b 100644 --- a/modules/c++/std/include/import/std.h +++ b/modules/c++/std/include/import/std.h @@ -102,6 +102,7 @@ CODA_OSS_disable_warning_system_header_push #include #include #include +#include CODA_OSS_disable_warning_pop diff --git a/modules/c++/std/include/std/mdspan b/modules/c++/std/include/std/mdspan new file mode 100644 index 000000000..b25c5447d --- /dev/null +++ b/modules/c++/std/include/std/mdspan @@ -0,0 +1,46 @@ +/* ========================================================================= + * This file is part of std-c++ + * ========================================================================= + * + * Copyright 2023, Maxar Technologies, Inc. + * + * std-c++ is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; If not, http://www.gnu.org/licenses/. + * + */ +#pragma once + +#include "coda_oss/mdspan.h" +#include "coda_oss/CPlusPlus.h" + +// Make it (too?) easy for clients to get our various std:: implementations +#ifndef CODA_OSS_NO_std_mdspan + #if CODA_OSS_cpp23 + #include + #define CODA_OSS_NO_std_mdspan 1 // part of C++23 + #else + #define CODA_OSS_NO_std_mdspan 0 // use our own + #endif +#endif + +#if !CODA_OSS_NO_std_mdspan +namespace std // This is slightly uncouth: we're not supposed to augment "std". +{ + using coda_oss::mdspan; + using coda_oss::dextents; +} +#ifndef __cpp_lib_mdspan +#define __cpp_lib_mdspan 202002L // https://en.cppreference.com/w/cpp/feature_test#cpp_lib_mdspan +#endif + +#endif // CODA_OSS_NO_std_mdspan diff --git a/modules/c++/std/include/std/span b/modules/c++/std/include/std/span index 407d7d54f..6eb29377b 100644 --- a/modules/c++/std/include/std/span +++ b/modules/c++/std/include/std/span @@ -23,6 +23,7 @@ #define CODA_OSS_std_span_INCLUDED_ #include "coda_oss/span.h" +#include "coda_oss/CPlusPlus.h" // Make it (too?) easy for clients to get our various std:: implementations #ifndef CODA_OSS_NO_std_span @@ -47,4 +48,50 @@ namespace std // This is slightly uncouth: we're not supposed to augment "std". #endif // CODA_OSS_NO_std_span +// Make it (too?) easy for clients to get our various std:: implementations +#ifndef CODA_OSS_NO_nonmember_container_access + // https://en.cppreference.com/w/cpp/feature_test#cpp_lib_nonmember_container_access + #if defined(__cpp_lib_nonmember_container_access) && (__cpp_lib_nonmember_container_access >= 201411L) + #define CODA_OSS_NO_nonmember_container_access 1 // no need to muck with `std` + #else + // It seems MSVC has this even at C++14, see + // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 + #if _MSC_VER >= 1900 // Visual Studio 2015 (14.0) + #define CODA_OSS_NO_nonmember_container_access 1 // no need to muck with `std` + #else + #define CODA_OSS_NO_nonmember_container_access 0 // use our own + #endif + #endif +#endif + +#if !CODA_OSS_NO_nonmember_container_access +namespace std // This is slightly uncouth: we're not supposed to augment "std". +{ + using coda_oss::size; +} +#ifndef __cpp_lib_nonmember_container_access +#define __cpp_lib_nonmember_container_access 201411L // https://en.cppreference.com/w/cpp/feature_test +#endif +#endif // CODA_OSS_NO_nonmember_container_access + +// Make it (too?) easy for clients to get our various std:: implementations +#ifndef CODA_OSS_NO_std_ssize + // https://en.cppreference.com/w/cpp/feature_test#cpp_lib_ssize + #if defined(__cpp_lib_ssize) && (__cpp_lib_ssize >= 201902L) + #define CODA_OSS_NO_std_ssize 1 // no need to muck with `std` + #else + #define CODA_OSS_NO_std_ssize 0 // use our own + #endif +#endif + +#if !CODA_OSS_NO_std_ssize +namespace std // This is slightly uncouth: we're not supposed to augment "std". +{ + using coda_oss::ssize; +} +#ifndef __cpp_lib_ssize +#define __cpp_lib_ssize 201902L // https://en.cppreference.com/w/cpp/feature_test +#endif +#endif // CODA_OSS_NO_std_ssize + #endif // CODA_OSS_std_span_INCLUDED_ \ No newline at end of file diff --git a/modules/c++/str/include/str/Convert.h b/modules/c++/str/include/str/Convert.h index 83afad5b7..ca154a6a1 100644 --- a/modules/c++/str/include/str/Convert.h +++ b/modules/c++/str/include/str/Convert.h @@ -55,13 +55,56 @@ template int getPrecision(const types::ComplexInteger&); // Note that std::to_string() doesn't necessarily generate the same output as writing // to std::cout; see https://en.cppreference.com/w/cpp/string/basic_string/to_string template -std::string toString(const T& value) +std::string toString_(const T& value) { std::ostringstream buf; buf.precision(getPrecision(value)); buf << std::boolalpha << value; return buf.str(); } +template +inline std::string toString(const T& value) +{ + return toString_(value); +} + +// https://en.cppreference.com/w/cpp/string/basic_string/to_string +inline auto toString(int value) +{ + return toString_(value); +} +inline auto toString(long value) +{ + return toString_(value); +} +inline auto toString(long long value) +{ + return toString_(value); +} +inline auto toString(unsigned value) +{ + return toString_(value); +} +inline auto toString(unsigned long value) +{ + return toString_(value); +} +inline auto toString(unsigned long long value) +{ + return toString_(value); +} +inline auto toString(float value) +{ + return toString_(value); +} +inline auto toString(double value) +{ + return toString_(value); +} +inline auto toString(long double value) +{ + return toString_(value); +} inline std::string toString(uint8_t value) { @@ -85,27 +128,25 @@ inline std::string toString(const std::string& value) { return value; } -// can't be a template; `bool` overload above is a better match +// Prevent the template above from getting used; instead, use routines from **Encoding.h**. +std::string toString(const std::wstring&) = delete; +std::string toString(const std::u16string&) = delete; +std::string toString(const std::u32string&) = delete; +std::string toString(const coda_oss::u8string&) = delete; +std::string toString(const str::W1252string&) = delete; + inline std::string toString(std::string::const_pointer pStr) { return toString(std::string(pStr)); } - -// The resultant `std::string`s have "native" encoding (which is lost) depending -// on the platform: UTF-8 on Linux and Windows-1252 on Windows. -CODA_OSS_API std::string toString(const coda_oss::u8string&); -CODA_OSS_API std::string toString(const str::W1252string&); -CODA_OSS_API std::string toString(const std::wstring&); // input is UTF-16 or UTF-32 depending on the platform // can't be a template; `bool` overload above is a better match std::string toString(std::wstring::const_pointer) = delete; // only used in unittests std::string toString(std::u16string::const_pointer) = delete; // only used in unittests std::string toString(std::u32string::const_pointer) = delete; // only used in unittests -CODA_OSS_API coda_oss::u8string u8FromString(const std::string&); // platform determines Windows-1252 or UTF-8 input - inline std::ostream& operator<<(std::ostream& os, const coda_oss::u8string& s) { - os << toString(s); + os << to_native(s); return os; } @@ -127,13 +168,6 @@ inline std::string toString(const T& real, const T& imag) return toString(std::complex(real, imag)); } -CODA_OSS_API std::wstring toWString(const std::string&); // platform determines Windows-1252 or UTF-8 input and output encoding -CODA_OSS_API std::wstring toWString(const coda_oss::u8string&); // platform determines UTF-16 or UTF-32 output encoding -CODA_OSS_API std::wstring toWString(const str::W1252string&); // platform determines UTF-16 or UTF-32 output encoding - -CODA_OSS_API coda_oss::u8string u8FromWString(const std::wstring&); // platform determines UTF16 or UTF-32 input - - template T toType(const std::string& s) { diff --git a/modules/c++/str/include/str/Encoding.h b/modules/c++/str/include/str/Encoding.h index 9709ff5c6..4dbaa76f5 100644 --- a/modules/c++/str/include/str/Encoding.h +++ b/modules/c++/str/include/str/Encoding.h @@ -40,6 +40,8 @@ namespace str { +namespace details +{ template inline auto cast(const TChar* s) { @@ -52,24 +54,26 @@ inline auto cast(const TChar* s) static_assert(sizeof(*retval) == sizeof(*s), "sizeof(*TReturn) != sizeof(*TChar)"); return retval; } +} template inline auto c_str(const std::basic_string& s) { using return_t = typename TBasicStringT::const_pointer; - return cast(s.c_str()); + return details::cast(s.c_str()); } template -inline TBasicStringT str(const std::basic_string& s) +inline auto str(const std::basic_string& s) { return TBasicStringT(c_str(s), s.length()); // avoid extra strlen() call } template inline TBasicStringT make_string(TChar* p) { - using return_t = typename TBasicStringT::const_pointer; - return cast(p); // copy into RV + using const_pointer = typename TBasicStringT::const_pointer; + return details::cast(p); // copy into RV } +/************************************************************************/ // When the encoding is important, we want to "traffic" in coda_oss::u8string (UTF-8), not // str::W1252string (Windows-1252) or std::string (unknown). Make it easy to get those from other encodings. CODA_OSS_API coda_oss::u8string to_u8string(str::W1252string::const_pointer, size_t); @@ -79,16 +83,70 @@ inline coda_oss::u8string to_u8string(coda_oss::u8string::const_pointer p, size_ { return coda_oss::u8string(p, sz); } +// Explicit overloads so template can be used for a different purpose. +inline auto to_u8string(const coda_oss::u8string& s) +{ + return to_u8string(s.c_str(), s.length()); +} +inline auto to_u8string(const str::W1252string& s) +{ + return to_u8string(s.c_str(), s.length()); +} +inline auto to_u8string(const std::u16string& s) +{ + return to_u8string(s.c_str(), s.length()); +} +inline auto to_u8string(const std::u32string& s) +{ + return to_u8string(s.c_str(), s.length()); +} +// These two routines are "dangerous" as they make it easy to convert +// a `char*` **already** in UTF-8 encoding to UTF-8; the result is garbage. +// Use u8FromNative() or u8FromNative() which is a bit more explicit. +coda_oss::u8string to_u8string(std::string::const_pointer, size_t) = delete; +coda_oss::u8string to_u8string(std::wstring::const_pointer, size_t) = delete; + +// Template parameter specifies how `std::string` is encoded. As opposed +// to figuring it out a run-time based on the platform. +template +inline auto to_u8string(const std::string& s) // UTF-8 or Windows-1252 +{ + return to_u8string(str::c_str(s), s.length()); +} +template +inline auto to_u8string(const std::wstring& s) // UTF-16 or UTF-32 +{ + return to_u8string(str::c_str(s), s.length()); +} +/************************************************************************/ // UTF-16 is the default on Windows. CODA_OSS_API std::u16string to_u16string(coda_oss::u8string::const_pointer, size_t); CODA_OSS_API std::u16string to_u16string(str::W1252string::const_pointer, size_t); +inline auto to_u16string(const coda_oss::u8string& s) +{ + return to_u16string(s.c_str(), s.length()); +} +inline auto to_u16string(const str::W1252string& s) +{ + return to_u16string(s.c_str(), s.length()); +} +/************************************************************************/ // UTF-32 is convenient because each code-point is a single 32-bit integer. // It's typically std::wstring::value_type on Linux, but NOT Windows. CODA_OSS_API std::u32string to_u32string(coda_oss::u8string::const_pointer, size_t); CODA_OSS_API std::u32string to_u32string(str::W1252string::const_pointer, size_t); +inline auto to_u32string(const coda_oss::u8string& s) +{ + return to_u32string(s.c_str(), s.length()); +} +inline auto to_u32string(const str::W1252string& s) +{ + return to_u32string(s.c_str(), s.length()); +} +/************************************************************************/ // Windows-1252 (almost the same as ISO8859-1) is the default single-byte encoding on Windows. CODA_OSS_API str::W1252string to_w1252string(coda_oss::u8string::const_pointer p, size_t sz); inline auto to_w1252string(const coda_oss::u8string& s) @@ -96,26 +154,58 @@ inline auto to_w1252string(const coda_oss::u8string& s) return to_w1252string(s.c_str(), s.length()); } -// These two routines are "dangerous" as they make it easy to convert -// a `char*` **already** in UTF-8 encoding to UTF-8; the result is garbage. -// Use u8FromString() or u8FromWString() which is a bit more explicit. -coda_oss::u8string to_u8string(std::string::const_pointer, size_t) = delete; -coda_oss::u8string to_u8string(std::wstring::const_pointer, size_t) = delete; +/************************************************************************/ -template -inline auto to_u8string(const std::basic_string& s) +inline auto u8FromNative(const std::string& s) // platform determines Windows-1252 or UTF-8 input { - return to_u8string(s.c_str(), s.length()); + #if _WIN32 + const auto p = str::c_str(s); // std::string is Windows-1252 on Windows + #else + const auto p = str::c_str(s); // assume std::string is UTF-8 on any non-Windows platform + #endif + return str::to_u8string(p, s.length()); } -template -inline auto to_u16string(const std::basic_string& s) + +namespace details { - return to_u16string(s.c_str(), s.length()); +inline auto c_str(const std::wstring& s) +{ + #if _WIN32 + return str::c_str(s); // std::wstring is UTF-16 on Windows + #else + return str::c_str(s); // assume std::wstring is UTF-32 on any non-Windows platform + #endif } -template -inline auto to_u32string(const std::basic_string& s) +} +inline auto u8FromNative(const std::wstring& s) // platform determines UTF16 or UTF-32 input { - return to_u32string(s.c_str(), s.length()); + return str::to_u8string(details::c_str(s), s.length()); +} + +/************************************************************************/ + +// The resultant `std::string`s have "native" encoding (which is lost) depending +// on the platform: UTF-8 on Linux and Windows-1252 on Windows. +namespace details +{ + inline std::string to_string(const std::string& s) + { + return s; + } +CODA_OSS_API std::string to_string(const coda_oss::u8string&); +CODA_OSS_API std::string to_string(const std::wstring&); // input is UTF-16 or UTF-32 depending on the platform +CODA_OSS_API std::wstring to_wstring(const std::string&); // platform determines Windows-1252 or UTF-8 input and output encoding +CODA_OSS_API std::wstring to_wstring(const coda_oss::u8string&); // platform determines UTF-16 or UTF-32 output encoding +} +namespace testing +{ +CODA_OSS_API std::string to_string(const str::W1252string&); +CODA_OSS_API std::wstring to_wstring(const str::W1252string&); // platform determines UTF-16 or UTF-32 output encoding +} + +inline std::string to_native(const coda_oss::u8string& s) // cf., std::filesystem::native(), https://en.cppreference.com/w/cpp/filesystem/path/native +{ + return details::to_string(s); } } diff --git a/modules/c++/str/include/str/Format.h b/modules/c++/str/include/str/Format.h index 3ecb9e81a..6261e204d 100644 --- a/modules/c++/str/include/str/Format.h +++ b/modules/c++/str/include/str/Format.h @@ -26,8 +26,8 @@ #define CODA_OSS_str_Format_h_INCLUDED_ #include -#include -#include +#include +#include #include @@ -35,134 +35,185 @@ namespace str { - CODA_OSS_API std::string Format(const char* format, ...); +namespace details +{ +CODA_OSS_API std::string Format_(const char* format, ...); + +inline auto Format(const char* format) +{ + return Format_(format); +} + +template +inline auto Format(const char* format, const T1& t1) +{ + return Format_(format, t1); +} +template +inline auto Format(const char* format, const T1& t1, const T2& t2) +{ + return Format_(format, t1, t2); +} +template +inline auto Format(const char* format, const T1& t1, const T2& t2, const T3& t3) +{ + return Format_(format, t1, t2, t3); +} +template +inline auto Format(const char* format, const T1& t1, const T2& t2, const T3& t3, const T4& t4) +{ + return Format_(format, t1, t2, t3, t4); +} } + /*! * \param format The format * \param ... Any printf like thing */ -//CODA_OSS_API std::string format(const char* format, ...); -inline auto FmtX(const char* format) +inline auto Format(const char* format) { - return str::Format(format); + return details::Format(format); } -inline auto FmtX(const char* format, const char* pStr) +inline auto Format(const char* format, const char* pStr) +{ + return details::Format(format, pStr); +} +inline auto Format(const char* format, const std::string& s) { - return str::Format(format, pStr); + return Format(format, s.c_str()); } -inline auto FmtX(const char* format, const std::string& s) +inline auto Format(const char* format, int i) { - return str::Format(format, s.c_str()); + return details::Format(format, i); } -inline auto FmtX(const char* format, int i) +inline auto Format(const char* format, uint32_t i) { - return str::Format(format, i); + return details::Format(format, i); } -inline auto FmtX(const char* format, uint32_t i) +inline auto Format(const char* format, ptrdiff_t l) { - return str::Format(format, i); + return details::Format(format, l); } -inline auto FmtX(const char* format, ptrdiff_t l) +inline auto Format(const char* format, size_t ul) { - return str::Format(format, l); + return details::Format(format, ul); } -inline auto FmtX(const char* format, size_t ul) +inline auto Format(const char* format, float f) { - return str::Format(format, ul); + return details::Format(format, f); } -inline auto FmtX(const char* format, float f) +inline auto Format(const char* format, double d) { - return str::Format(format, f); + return details::Format(format, d); } -inline auto FmtX(const char* format, double d) +inline auto Format(const char* format, const void* p) { - return str::Format(format, d); + return details::Format(format, p); } -inline auto FmtX(const char* format, char ch, const char* pStr) +inline auto Format(const char* format, char ch, const char* pStr) +{ + return details::Format(format, ch, pStr); +} +inline auto Format(const char* format, char ch, const std::string& s) +{ + return Format(format, ch, s.c_str()); +} +inline auto Format(const char* format, const std::string& s1, const std::string& s2) { - return str::Format(format, ch, pStr); + return details::Format(format, s1.c_str(), s2.c_str()); } -inline auto FmtX(const char* format, char ch, const std::string& s) +inline auto Format(const char* format, const std::string& s, size_t ul) { - return str::Format(format, ch, s.c_str()); + return details::Format(format, s.c_str(), ul); } -inline auto FmtX(const char* format, const std::string& s1, const std::string& s2) +inline auto Format(const char* format, char ch1, char ch2) { - return str::Format(format, s1.c_str(), s2.c_str()); + return details::Format(format, ch1, ch2); } -inline auto FmtX(const char* format, const std::string& s, size_t ul) +inline auto Format(const char* format, int i1, int i2) { - return str::Format(format, s.c_str(), ul); + return details::Format(format, i1, i2); } -inline auto FmtX(const char* format, char ch1, char ch2) +inline auto Format(const char* format, long l1, long l2) { - return str::Format(format, ch1, ch2); + return details::Format(format, l1, l2); } -inline auto FmtX(const char* format, long l1, long l2) +inline auto Format(const char* format, uint32_t ui1, uint32_t ui2) { - return str::Format(format, l1, l2); + return details::Format(format, ui1, ui2); } -inline auto FmtX(const char* format, size_t ul1, size_t ul2) +inline auto Format(const char* format, size_t ul1, size_t ul2) { - return str::Format(format, ul1, ul2); + return details::Format(format, ul1, ul2); } -inline auto FmtX(const char* format, double d1, double d2) +inline auto Format(const char* format, size_t ul1, int i2) { - return str::Format(format, d1, d2); + return details::Format(format, ul1, i2); } -inline auto FmtX(const char* format, int i, const char* pStr) +inline auto Format(const char* format, double d1, double d2) { - return str::Format(format, i, pStr); + return details::Format(format, d1, d2); } -inline auto FmtX(const char* fmt, int i, const std::string& s) +inline auto Format(const char* format, int i, const char* pStr) { - return FmtX(fmt, i, s.c_str()); + return details::Format(format, i, pStr); +} +inline auto Format(const char* fmt, int i, const std::string& s) +{ + return Format(fmt, i, s.c_str()); } -inline auto FmtX(const char* format, char ch1, char ch2, const std::string& s) +inline auto Format(const char* format, char ch1, char ch2, const std::string& s) { - return str::Format(format, ch1, ch2, s.c_str()); + return details::Format(format, ch1, ch2, s.c_str()); } -inline auto FmtX(const char* format, int i1, int i2, unsigned long ul) +inline auto Format(const char* format, int i1, int i2, unsigned long ul) { - return str::Format(format, i1, i2, ul); + return details::Format(format, i1, i2, ul); } -inline auto FmtX(const char* format, int i1, int i2, int i3) +inline auto Format(const char* format, int i1, int i2, int i3) { - return str::Format(format, i1, i2, i3); + return details::Format(format, i1, i2, i3); } -inline auto FmtX(const char* format, float f1, float f2, float f3) +inline auto Format(const char* format, float f1, float f2, float f3) { - return str::Format(format, f1, f2, f3); + return details::Format(format, f1, f2, f3); } -inline std::string FmtX(const char* format, const std::string& s1, int i2, int i3) +inline std::string Format(const char* format, const std::string& s1, int i2, int i3) { - return str::Format(format, s1.c_str(), i2, i3); + return details::Format(format, s1.c_str(), i2, i3); } -inline auto FmtX(const char* format, const std::string& s1, const std::string& s2, uint32_t ui) +inline auto Format(const char* format, const std::string& s1, const std::string& s2, uint32_t ui) { - return str::Format(format, s1.c_str(), s2.c_str(), ui); + return details::Format(format, s1.c_str(), s2.c_str(), ui); } -inline auto FmtX(const char* format, const std::string& s1, const std::string& s2, const std::string& s3) +inline auto Format(const char* format, const std::string& s1, const std::string& s2, const std::string& s3) { - return str::Format(format, s1.c_str(), s2.c_str(), s3.c_str()); + return details::Format(format, s1.c_str(), s2.c_str(), s3.c_str()); } -inline auto FmtX(const char* format, int i1, int i2, int i3, int i4) +inline auto Format(const char* format, int i1, int i2, int i3, int i4) +{ + return details::Format(format, i1, i2, i3, i4); +} +inline auto Format(const char* format, uint32_t ui1, uint32_t ui2, uint32_t ui3, uint32_t ui4) { - return str::Format(format, i1, i2, i3, i4); + return details::Format(format, ui1, ui2, ui3, ui4); } -inline auto FmtX(const char* format, const char* pStr1, const std::string& s2, const char* pStr3, const std::string& s4) +inline auto Format(const char* format, const char* pStr1, const std::string& s2, const char* pStr3, const std::string& s4) { - return str::Format(format, pStr1, s2.c_str(), pStr3, s4.c_str()); + return details::Format(format, pStr1, s2.c_str(), pStr3, s4.c_str()); } -inline auto FmtX(const char* format, const std::string& s1, int i2, const std::string& s3, int i4) +inline auto Format(const char* format, const std::string& s1, int i2, const std::string& s3, int i4) { - return str::Format(format, s1.c_str(), i2, s3.c_str(), i4); + return details::Format(format, s1.c_str(), i2, s3.c_str(), i4); +} } +#define FmtX(format, ...) str::Format(format, __VA_ARGS__) + #endif // CODA_OSS_str_Format_h_INCLUDED_ diff --git a/modules/c++/str/include/str/Manip.h b/modules/c++/str/include/str/Manip.h index ee95a4663..5efd950d2 100644 --- a/modules/c++/str/include/str/Manip.h +++ b/modules/c++/str/include/str/Manip.h @@ -1,4 +1,4 @@ -/* ========================================================================= +/* ========================================================================= * This file is part of str-c++ * ========================================================================= * @@ -34,6 +34,7 @@ #include "coda_oss/CPlusPlus.h" #include "coda_oss/string.h" #include "str/Convert.h" +#include "str/W1252string.h" namespace str { @@ -168,10 +169,79 @@ CODA_OSS_API std::vector split(const std::string& s, const std::string& splitter = " ", size_t maxSplit = std::string::npos); +/***********************************************************************************/ //! Uses std::transform to convert all chars to lower case //! Uses std::transform to convert all chars to upper case -CODA_OSS_API void lower(std::string& s); -CODA_OSS_API void upper(std::string& s); +//CODA_OSS_API void lower(std::string& s); +//CODA_OSS_API void upper(std::string& s); +// +// Using std::transform() with ::toupper() is considerably slower than a lookup-table +CODA_OSS_API void ascii_lower(std::string& s); +inline void lower(std::string& s) +{ + ascii_lower(s); +} +inline std::string lower(const std::string& s) +{ + std::string retval = s; + lower(retval); + return retval; +} + +CODA_OSS_API void ascii_upper(std::string& s); +inline void upper(std::string& s) +{ + ascii_upper(s); +} +inline std::string upper(const std::string& s) +{ + std::string retval = s; + upper(retval); + return retval; +} + +// At this point, you might want to `lower()` and `upper()` for UTF-8 and/or +// Windows-1252. That can be done, but ... our needs are mostly English (99.9%) +// with a very occassional smattering of (Canadian-) French. We've gotten by this +// long without being able to upper/lower 'ä' and 'Ä' and there's no current +// requirement to do so. +// +// Furthermore, while Windows-1252 is easy as it's a single-byte encoding and +// covers many european languages, the standard is UTF-8. Changing case +// with Unicode is quite a bit more complicated as there can be +// numerous rules for various languages. For example, in German, the "old +// rules" where that 'ß' was uppercased to "SS"; however, there is now a 'ẞ'. +// And then there are semantics: in German, no word can begin with 'ß' (or 'ẞ') +// making "ßanything" rather non-sensical. +// +// So for now (until there is a real use case), just "define these problems +// away" by not exposing `w1252_lower()`, `utf8_upper()`, etc. +/* +// With Windows-1252 encoding, we can convert between 'ä' and 'Ä'. +CODA_OSS_API void w1252_lower(std::string& s); +CODA_OSS_API void w1252_upper(std::string& s); +CODA_OSS_API void lower(str::W1252string& s); +CODA_OSS_API void upper(str::W1252string& s); + +// Hooking up UTF-8 for completeness and unit-testing. +// ** THESE ROUTINES ARE SLOW ** +// Performance improvements can be made, but nobody needs such right now. +CODA_OSS_API void utf8_lower(std::string& s); +CODA_OSS_API void utf8_upper(std::string& s); +CODA_OSS_API void lower(coda_oss::u8string& s); +CODA_OSS_API void upper(coda_oss::u8string& s); +*/ + +// I've already got these hooked up, keep the code around ... long ugly +// names to discourage use. +CODA_OSS_API str::Windows1252_T to_w1252_upper(str::Windows1252_T); +CODA_OSS_API str::Windows1252_T to_w1252_lower(str::Windows1252_T); + +/***********************************************************************************/ + +// Using std::transform() with ::toupper() is considerably slower than a lookup-table +CODA_OSS_API void ascii_lower(std::string& s); +CODA_OSS_API void ascii_upper(std::string& s); /*! * Replaces any characters that are invalid in XML (&, <, >, ', ") with their diff --git a/modules/c++/str/source/Convert.cpp b/modules/c++/str/source/Convert.cpp index f2ae3d9f9..b8a2bc741 100644 --- a/modules/c++/str/source/Convert.cpp +++ b/modules/c++/str/source/Convert.cpp @@ -42,32 +42,25 @@ template<> std::string str::toType(const std::string& s) template<> bool str::toType(const std::string& s) { - std::string ss = s; - str::lower(ss); - - if (ss == "true") + if (eq(s, "true")) // case-insensitive compare { return true; } - else if (ss == "false") + if (eq(s, "false")) // case-insensitive compare { return false; } - else if (str::isNumeric(ss)) + + // no need for lower(), digits don't have case + if (str::isNumeric(s)) { int value(0); - std::stringstream buf(ss); + std::stringstream buf(s); buf >> value; return (value != 0); } - else - { - throw except::BadCastException(except::Context(__FILE__, __LINE__, - std::string(""), std::string(""), - std::string("Invalid bool: '") + s + std::string("'"))); - } - return false; + throw except::BadCastException(except::Context(__FILE__, __LINE__, "", "", "Invalid bool: '" + s + "'")); } long long str::strtoll(const char *str, char **endptr, int base) diff --git a/modules/c++/str/source/Encoding.cpp b/modules/c++/str/source/Encoding.cpp index 98795b259..c9833ea88 100644 --- a/modules/c++/str/source/Encoding.cpp +++ b/modules/c++/str/source/Encoding.cpp @@ -29,10 +29,10 @@ #endif #include -#include #include #include #include +#include #include "gsl/gsl.h" #include "config/compiler_extensions.h" @@ -48,85 +48,86 @@ CODA_OSS_disable_warning(-Wshadow) #include "str/utf8.h" CODA_OSS_disable_warning_pop -//// "sys" depends on "str" so can't use sys::PlatformType -//enum class PlatformType -//{ -// Windows, -// Linux, -// // MacOS -//}; -#if _WIN32 -//static constexpr auto Platform = PlatformType::Windows; -#elif defined(_POSIX_C_SOURCE) -//static constexpr auto Platform = PlatformType::Linux; -#else -#error "Unknown platform" -#endif - // Need to look up characters from \x80 (EURO SIGN) to \x9F (LATIN CAPITAL LETTER Y WITH DIAERESIS) // in a map: http://www.unicode.org/Public/MAPPINGS/VENDORS/MICSFT/WINDOWS/CP1252.TXT -inline coda_oss::u8string utf8_(uint32_t i) +static inline coda_oss::u8string utf8_(char32_t i) { const auto ch = gsl::narrow(i); return str::to_u8string(std::u32string{ch}); } -static const auto& Windows1252_x80_x9F_to_u8string() -{ - static const std::map retval { - {0x80, utf8_(0x20AC) } // EURO SIGN - // , {0x81, replacement_character } // UNDEFINED - , {0x82, utf8_(0x201A) } // SINGLE LOW-9 QUOTATION MARK - , {0x83, utf8_(0x0192) } // LATIN SMALL LETTER F WITH HOOK - , {0x84, utf8_(0x201E) } // DOUBLE LOW-9 QUOTATION MARK - , {0x85, utf8_(0x2026) } // HORIZONTAL ELLIPSIS - , {0x86, utf8_(0x2020) } // DAGGER - , {0x87, utf8_(0x2021) } // DOUBLE DAGGER - , {0x88, utf8_(0x02C6) } // MODIFIER LETTER CIRCUMFLEX ACCENT - , {0x89, utf8_(0x2030) } // PER MILLE SIGN - , {0x8A, utf8_(0x0160) } // LATIN CAPITAL LETTER S WITH CARON - , {0x8B, utf8_(0x2039) } // SINGLE LEFT-POINTING ANGLE QUOTATION MARK - , {0x8C, utf8_(0x0152) } // LATIN CAPITAL LIGATURE OE - //, {0x8D, replacement_character } // UNDEFINED - , {0x8E, utf8_(0x017D) } // LATIN CAPITAL LETTER Z WITH CARON - //, {0x8F, replacement_character } // UNDEFINED - //, {0x90, replacement_character } // UNDEFINED - , {0x91, utf8_(0x2018) } // LEFT SINGLE QUOTATION MARK - , {0x92, utf8_(0x2019) } // RIGHT SINGLE QUOTATION MARK - , {0x93, utf8_(0x201C) } // LEFT DOUBLE QUOTATION MARK - , {0x94, utf8_(0x201D) } // RIGHT DOUBLE QUOTATION MARK - , {0x95, utf8_(0x2022) } // BULLET - , {0x96, utf8_(0x2013) } // EN DASH - , {0x97, utf8_(0x2014) } // EM DASH - , {0x98, utf8_(0x02DC) } // SMALL TILDE - , {0x99, utf8_(0x2122) } // TRADE MARK SIGN - , {0x9A, utf8_(0x0161) } // LATIN SMALL LETTER S WITH CARON - , {0x9B, utf8_(0x203A) } // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - , {0x9C, utf8_(0x0153) } // LATIN SMALL LIGATURE OE - //, {0x9D, replacement_character } // UNDEFINED - , {0x9E, utf8_(0x017E) } // LATIN SMALL LETTER Z WITH CARON - , {0x9F, utf8_(0x0178) } // LATIN CAPITAL LETTER Y WITH DIAERESIS +// https://en.wikipedia.org/wiki/Windows-1252 +// > According to the information on Microsoft's and the Unicode Consortium's +// > websites, positions 81, 8D, 8F, 90, and 9D are unused; however, the +// > Windows API `MultiByteToWideChar` maps these to the corresponding +// > C1 control codes. The "best fit" mapping documents this behavior, too. +static const auto& Windows1252_x80_x9F_to_u8string_() +{ + static const std::map retval{ + {U'\x80', utf8_(U'\x20AC') } // EURO SIGN + , {U'\x81', utf8_(U'\x0081') } // UNDEFINED; _bstr_t just preserves these values, do the same // , {U'\x81', replacement_character } // UNDEFINED + , {U'\x82', utf8_(U'\x201A') } // SINGLE LOW-9 QUOTATION MARK + , {U'\x83', utf8_(U'\x0192') } // LATIN SMALL LETTER F WITH HOOK + , {U'\x84', utf8_(U'\x201E') } // DOUBLE LOW-9 QUOTATION MARK + , {U'\x85', utf8_(U'\x2026') } // HORIZONTAL ELLIPSIS + , {U'\x86', utf8_(U'\x2020') } // DAGGER + , {U'\x87', utf8_(U'\x2021') } // DOUBLE DAGGER + , {U'\x88', utf8_(U'\x02C6') } // MODIFIER LETTER CIRCUMFLEX ACCENT + , {U'\x89', utf8_(U'\x2030') } // PER MILLE SIGN + , {U'\x8A', utf8_(U'\x0160') } // LATIN CAPITAL LETTER S WITH CARON + , {U'\x8B', utf8_(U'\x2039') } // SINGLE LEFT-POINTING ANGLE QUOTATION MARK + , {U'\x8C', utf8_(U'\x0152') } // LATIN CAPITAL LIGATURE OE + , {U'\x8D', utf8_(U'\x008D') } // UNDEFINED; _bstr_t just preserves these values, do the same // , {U'\x8D', replacement_character } // UNDEFINED + , {U'\x8E', utf8_(U'\x017D') } // LATIN CAPITAL LETTER Z WITH CARON + , {U'\x8F', utf8_(U'\x008F') } // UNDEFINED; _bstr_t just preserves these values, do the same // , {U'\x8F', replacement_character } // UNDEFINED + , {U'\x90', utf8_(U'\x0090') } // UNDEFINED; _bstr_t just preserves these values, do the same // , {U'\x90', replacement_character } // UNDEFINED + , {U'\x91', utf8_(U'\x2018') } // LEFT SINGLE QUOTATION MARK + , {U'\x92', utf8_(U'\x2019') } // RIGHT SINGLE QUOTATION MARK + , {U'\x93', utf8_(U'\x201C') } // LEFT DOUBLE QUOTATION MARK + , {U'\x94', utf8_(U'\x201D') } // RIGHT DOUBLE QUOTATION MARK + , {U'\x95', utf8_(U'\x2022') } // BULLET + , {U'\x96', utf8_(U'\x2013') } // EN DASH + , {U'\x97', utf8_(U'\x2014') } // EM DASH + , {U'\x98', utf8_(U'\x02DC') } // SMALL TILDE + , {U'\x99', utf8_(U'\x2122') } // TRADE MARK SIGN + , {U'\x9A', utf8_(U'\x0161') } // LATIN SMALL LETTER S WITH CARON + , {U'\x9B', utf8_(U'\x203A') } // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + , {U'\x9C', utf8_(U'\x0153') } // LATIN SMALL LIGATURE OE + , {U'\x9D', utf8_(U'\x009D') } // UNDEFINED; _bstr_t just preserves these values, do the same // , {U'\x9D', replacement_character } // UNDEFINED + , {U'\x9E', utf8_(U'\x017E') } // LATIN SMALL LETTER Z WITH CARON + , {U'\x9F', utf8_(U'\x0178') } // LATIN CAPITAL LETTER Y WITH DIAERESIS }; return retval; } - static auto Windows1252_to_u8string() { - auto retval = Windows1252_x80_x9F_to_u8string(); + auto retval = Windows1252_x80_x9F_to_u8string_(); - // Add the ISO8859-1 values to the map too. 1) We're already looking + using value_type = coda_oss::u8string::value_type; + // Add the ASCII values to the map too. 1) We're already looking // in the map anyway for Windows-1252 characters. 2) Need map // entires for conversion from UTF-8 to Windows-1252. - for (std::u32string::value_type ch = 0xA0; ch <= 0xff; ch++) + for (char32_t ch = U'\x00'; ch < U'\x80'; ch++) + { + assert(retval.find(ch) == retval.end()); // be sure we're not clobbering anything! + + coda_oss::u8string s {static_cast(ch)}; + retval[ch] = std::move(s); + } + + // Ditto for ISO8859-1 ... + for (char32_t ch = U'\xA0'; ch <= U'\xff'; ch++) { + assert(retval.find(ch) == retval.end()); // be sure we're not clobbering anything! + // ISO8859-1 can be converted to UTF-8 with bit-twiddling - + // // https://stackoverflow.com/questions/4059775/convert-iso-8859-1-strings-to-utf-8-in-c-c // *out++=0xc2+(*in>0xbf), *out++=(*in++&0x3f)+0x80; const auto b1 = 0xc2 + (ch > 0xbf); const auto b2 = (ch & 0x3f) + 0x80; - coda_oss::u8string s {static_cast(b1)}; - s += coda_oss::u8string {static_cast(b2)}; + coda_oss::u8string s{static_cast(b1)}; + s += coda_oss::u8string{static_cast(b2)}; retval[ch] = std::move(s); } @@ -154,89 +155,82 @@ inline void append(std::u32string& result, const coda_oss::u8string& utf8) } template -static void fromWindows1252_(str::W1252string::value_type ch, std::basic_string& result, bool strict=false) +static void fromWindows1252_(str::W1252string::value_type ch, std::basic_string& result) { - // ASCII is the same in UTF-8 - if (ch < static_cast(0x80)) - { - using value_type = typename std::basic_string::value_type; - result += static_cast(ch); // ASCII - return; - } - static const auto map = Windows1252_to_u8string(); - const auto ch32 = static_cast(ch); + const auto ch32 = gsl::narrow(ch); const auto it = map.find(ch32); if (it != map.end()) { append(result, it->second); return; } - - switch (static_cast(ch)) + + // https://en.wikipedia.org/wiki/Windows-1252 + // > According to the information on Microsoft's and the Unicode + // Consortium's > websites, positions 81, 8D, 8F, 90, and 9D are unused; + // however, the > Windows API `MultiByteToWideChar` maps these to the + // corresponding > C1 control codes. The "best fit" mapping documents this + // behavior, too. + // static const auto replacement_character = utf8_(U'\xfffd'); + // append(result, replacement_character); + throw std::logic_error("Windows-1252 value not in map."); +} +template +class Windows1252_to_basic_string final +{ + static auto make_Windows1252_lookup() { - case 0x81: - case 0x8d: - case 0x8f: - case 0x90: - case 0x9d: - { - if (strict) + std::vector> retval(0xff + 1); + for (size_t i = 0; i <= 0xff; i++) { - // If the input text contains a character that isn't defined in Windows-1252; return a - // "replacement character." Yes, this will **corrupt** the input data as information is lost: - // https://en.wikipedia.org/wiki/Specials_(Unicode_block)#Replacement_character - static const coda_oss::u8string replacement_character = utf8_(0xfffd); - append(result, replacement_character); + const auto ch = static_cast(i); + fromWindows1252_(ch, retval[i]); } - else - { - // _bstr_t just preserves these values, do the same - append(result, utf8_(ch32)); - } - break; + return retval; } - default: - throw std::invalid_argument("Invalid Windows-1252 character."); + +public: + static const auto& getLookup() + { + static const auto lookup = make_Windows1252_lookup(); + return lookup; } -} -template -inline void w1252_to_string(str::W1252string::const_pointer p, size_t sz, std::basic_string& result) -{ - for (size_t i = 0; i < sz; i++) + + Windows1252_to_basic_string() = default; + auto operator()(str::W1252string::const_pointer p, size_t sz) const { - fromWindows1252_(p[i], result); + static const auto& lookup = getLookup(); + + std::basic_string retval; + for (size_t i = 0; i < sz; i++) + { + const auto ch = gsl::narrow(p[i]); + retval += lookup[ch]; + } + return retval; } -} -template -inline void w1252to8(str::W1252string::const_pointer p, size_t sz, std::basic_string& result) +}; +template +static inline void w1252_to_basic_string(str::W1252string::const_pointer p, size_t sz, std::basic_string& result) { - w1252_to_string(p, sz, result); + static const Windows1252_to_basic_string convert; + result = convert(p, sz); } -inline void w1252to16(str::W1252string::const_pointer p, size_t sz, std::u16string& result) + +static inline void w1252to16(str::W1252string::const_pointer p, size_t sz, std::u16string& result) { - w1252_to_string(p, sz, result); + w1252_to_basic_string(p, sz, result); #if defined(_WIN32) && (!defined(_NDEBUG) || defined(DEBUG)) - const _bstr_t bstr(std::string(str::cast(p), sz).c_str()); // no _bstr_t ctor taking sz + const _bstr_t bstr(std::string(str::details::cast(p), sz).c_str()); // no _bstr_t ctor taking sz const std::wstring wstr(static_cast(bstr)); assert(result == str::str(wstr)); #endif } -inline void w1252to32(str::W1252string::const_pointer p, size_t sz, std::u32string& result) -{ - w1252_to_string(p, sz, result); -} - -template -std::map kv_to_vk(const std::map& kv) +static inline void w1252to32(str::W1252string::const_pointer p, size_t sz, std::u32string& result) { - std::map retval; - for (const auto& p : kv) - { - retval[p.second] = p.first; - } - return retval; + w1252_to_basic_string(p, sz, result); } static void get_next_utf8_byte(coda_oss::u8string::const_pointer p, size_t sz, @@ -249,115 +243,127 @@ static void get_next_utf8_byte(coda_oss::u8string::const_pointer p, size_t sz, i++; // move to next byte // Bytes 2, 3 and 4 are always >= 0x80 (10xxxxxx), see https://en.wikipedia.org/wiki/UTF-8 - const auto b = static_cast(p[i]); - if (b < static_cast(0x80)) // 10xxxxxx + const auto b = gsl::narrow(p[i]); + if (b < gsl::narrow(0x80)) // 10xxxxxx { throw std::invalid_argument("Invalid next byte in UTF-8 encoding."); } utf8 += coda_oss::u8string{static_cast(b)}; } -template -static void utf8to1252(coda_oss::u8string::const_pointer p, size_t sz, std::basic_string& result, bool strict=false) +static void get_utf8_string(coda_oss::u8string::const_pointer p, size_t sz, size_t& i, coda_oss::u8string& utf8) { - using value_type = TChar; - for (size_t i = 0; i < sz; i++) + const auto b1 = gsl::narrow(p[i]); + if (b1 >= 0x80) // 0xxxxxxx { - const auto b1 = static_cast(p[i]); - - // ASCII is the same in UTF-8 - if (b1 < 0x80) // 0xxxxxxx - { - result += static_cast(b1); // ASCII - continue; - } - - auto utf8 = coda_oss::u8string{static_cast(b1)}; - get_next_utf8_byte(p, sz, i, utf8); if (b1 >= 0xE0) // 1110xxxx { // should be a 3- or 4-byte sequence - get_next_utf8_byte(p, sz, i, utf8); + get_next_utf8_byte(p, sz, i, utf8); if (b1 >= 0xF0) // 1111xxx { // should be a 4-byte sequence - get_next_utf8_byte(p, sz, i, utf8); + get_next_utf8_byte(p, sz, i, utf8); } } + } +} - static const auto map = kv_to_vk(Windows1252_to_u8string()); - const auto it = map.find(utf8); +template // may be stored in std::string or str::Windows1252 +class Utf_to_Windows1252 final +{ + template + void utf_to_1252(const TMap& map, const TUtf& utf, std::basic_string& result) const + { + auto w1252 = static_cast(0x7F); // + const auto it = map.find(utf); if (it != map.end()) { - result += static_cast(it->second); - } - else if (strict) - { - throw std::invalid_argument("UTF-8 sequence can't be converted to Windows-1252."); - //assert("UTF-8 sequence can't be converted to Windows-1252." && 0); - //result += static_cast(0x7F); // + w1252 = static_cast(it->second); } + #ifndef NDEBUG else { - // _bstr_t preserves these values - if (utf8.length() == 2) - { - result += static_cast(utf8[1]); - } - else - { - assert("UTF-8 sequence can't be converted to Windows-1252." && 0); - result += static_cast(0x7F); // - } + assert("UTF sequence can't be converted to Windows-1252." && 0); } + #endif // NDEBUG + result += w1252; } -} -static auto u16_to_Windows1252() -{ - // Find the corresponding UTF-16 value for every Windows-1252 input; - // obviously, most UTF-16 values can't be converted. Skip the first half - // as they're the same for ASCII. - std::map retval; - for (uint16_t i = 0x0080; i <= 0x00ff; i++) // **not** `uint8_t` to avoid wrap-around + static auto make_u16_map() { - const auto ch = static_cast(i); - const auto u16 = str::to_u16string(&ch, 1); - assert(u16.length() == 1); - retval[u16[0]] = ch; + // Find the corresponding UTF-16 value for every Windows-1252 input; + // obviously, most UTF-16 values can't be converted. + auto&& lookup = Windows1252_to_basic_string::getLookup(); + + std::map retval; + for (size_t i = 0; i <= 0xff; i++) // **not** `uint8_t` to avoid wrap-around + { + const auto u16 = lookup[i]; + assert(u16.length() == 1); // all values in Basic Multi-lingual Plane (BMP); no emojis, etc. + const auto ch = static_cast(i); + retval[u16[0]] = ch; + } + return retval; } - return retval; -} -static inline void utf16to1252(std::u16string::const_pointer p, size_t sz, std::string& result, bool strict=false) -{ - using value_type = std::string::value_type; - static const auto map = u16_to_Windows1252(); - for (size_t i = 0; i < sz; i++) + static auto make_utf8_map() { - const auto ch = p[i]; + // Find the corresponding UTF-8 value for every Windows-1252 input. + static const auto map = make_u16_map(); - if (ch < 0x0080) // ASCII + // Convert UTF-16 to UTF-8 + std::map retval; + for (auto&& kv : map) { - result += gsl::narrow(ch); - continue; + retval[utf8_(kv.first)] = kv.second; } + return retval; + } - const auto it = map.find(ch); - if (it != map.end()) - { - result += static_cast(it->second); - } - else if (strict) +public: + Utf_to_Windows1252() = default; + + auto operator()(std::u16string::const_pointer p, size_t sz) const + { + static const auto map = make_u16_map(); + + std::basic_string retval; + for (size_t i = 0; i < sz; i++) { - throw std::invalid_argument("UTF-16 sequence can't be converted to Windows-1252."); + const auto utf16 = p[i]; + utf_to_1252(map, utf16, retval); } - else + return retval; + } + + auto operator()(coda_oss::u8string::const_pointer p, size_t sz) const + { + static const auto map = make_utf8_map(); + + std::basic_string retval; + for (size_t i = 0; i < sz; i++) { - assert("UTF-16 sequence can't be converted to Windows-1252." && 0); - result += static_cast(0x7F); // + auto utf8 = coda_oss::u8string{p[i]}; + get_utf8_string(p, sz, i, utf8); + + utf_to_1252(map, utf8, retval); } + return retval; } +}; + +template +static inline void utf8to1252(coda_oss::u8string::const_pointer p, size_t sz, std::basic_string& result) +{ + static const Utf_to_Windows1252 convert; + result = convert(p, sz); +} + +static inline void utf16to1252(std::u16string::const_pointer p, size_t sz, std::string& result) +{ + static const Utf_to_Windows1252 convert; + result = convert(p, sz); } struct back_inserter final @@ -384,51 +390,60 @@ inline auto to_uXXstring(const std::basic_string& s) return str::to_u32string(p, s.length()); // assume std::wstring is UTF-32 everywhere except Windows #endif } -template -static std::wstring toWString_(const std::basic_string& s, bool is_utf8) + +template +struct basic_string_to_uXXstring_ final { }; +template +struct basic_string_to_uXXstring_ final +{ + auto operator()(const std::basic_string& s) const + { + return to_uXXstring(s); + } +}; +template +struct basic_string_to_uXXstring_ final +{ + auto operator()(const std::basic_string& s) const + { + return to_uXXstring(s); + } +}; +template +inline auto to_wstring_(const std::basic_string&s) { - - const auto result = is_utf8 ? to_uXXstring(s) - : to_uXXstring(s); + static const basic_string_to_uXXstring_ convert; + const auto result = convert(s); return str::str(result); } /***********************************************************************************/ -std::string str::toString(const coda_oss::u8string& s) +std::string str::details::to_string(const coda_oss::u8string& s) { #if _WIN32 std::string retval; utf8to1252(s.c_str(), s.length(), retval); return retval; #else - return str::str(s); + return str(s); #endif } -std::string str::toString(const str::W1252string& s) +std::string str::testing::to_string(const str::W1252string& s) { #if _WIN32 - return str::str(s); + return str(s); #else std::string retval; - w1252to8(s.c_str(), s.length(), retval); + w1252_to_basic_string(s.c_str(), s.length(), retval); return retval; #endif } -inline auto c_str_(const std::wstring& s) +std::string str::details::to_string(const std::wstring& s) { - #if _WIN32 - return str::c_str(s); // std::wstring is UTF-16 on Windows - #else - return str::c_str(s); // assume std::wstring is UTF-32 on any non-Windows platform - #endif -} - -std::string str::toString(const std::wstring& s) -{ - const auto p = c_str_(s); + const auto p = details::c_str(s); const auto sz = s.length(); std::string retval; @@ -440,39 +455,21 @@ std::string str::toString(const std::wstring& s) return retval; } -std::wstring str::toWString(const std::string& s) -{ - #if _WIN32 - return toWString_(s, false /*is_utf8*/); // Input is Windows-1252 on Windows - #else - return toWString_(s, true /*is_utf8*/); // Input is UTF-8 everywhere except Windows - #endif -} -std::wstring str::toWString(const coda_oss::u8string& s) -{ - return toWString_(s, true /*is_utf8*/); -} -std::wstring str::toWString(const str::W1252string& s) -{ - return toWString_(s, false /*is_utf8*/); -} - -inline auto c_str_(const std::string& s) +std::wstring str::details::to_wstring(const std::string& s) { #if _WIN32 - return str::c_str(s); // std::string is Windows-1252 on Windows + return to_wstring_(s); // Input is Windows-1252 on Windows #else - return str::c_str(s); // assume std::string is UTF-8 on any non-Windows platform - #endif + return to_wstring_(s); // Input is UTF-8 everywhere except Windows + #endif } -coda_oss::u8string str::u8FromString(const std::string& s) +std::wstring str::details::to_wstring(const coda_oss::u8string& s) { - return str::to_u8string(c_str_(s), s.length()); + return to_wstring_(s); } - -coda_oss::u8string str::u8FromWString(const std::wstring& s) +std::wstring str::testing::to_wstring(const str::W1252string& s) { - return str::to_u8string(c_str_(s), s.length()); + return to_wstring_(s); } /***********************************************************************************/ @@ -506,7 +503,7 @@ coda_oss::u8string str::to_u8string(std::u16string::const_pointer p, size_t sz) std::u16string str::to_u16string(coda_oss::u8string::const_pointer p_, size_t sz) { - auto p = str::cast(p_); + auto p = details::cast(p_); std::u16string retval; utf8::utf8to16(p, p + sz, std::back_inserter(retval)); return retval; @@ -514,7 +511,7 @@ std::u16string str::to_u16string(coda_oss::u8string::const_pointer p_, size_t sz std::u32string str::to_u32string(coda_oss::u8string::const_pointer p_, size_t sz) { - auto p = str::cast(p_); + auto p = details::cast(p_); std::u32string retval; utf8::utf8to32(p, p + sz, std::back_inserter(retval)); return retval; @@ -530,6 +527,6 @@ coda_oss::u8string str::to_u8string(std::u32string::const_pointer p, size_t sz) coda_oss::u8string str::to_u8string(W1252string::const_pointer p, size_t sz) { coda_oss::u8string retval; - w1252to8(p, sz, retval); + w1252_to_basic_string(p, sz, retval); return retval; } diff --git a/modules/c++/str/source/Format.cpp b/modules/c++/str/source/Format.cpp index 8fc1205c7..fdcfc8544 100644 --- a/modules/c++/str/source/Format.cpp +++ b/modules/c++/str/source/Format.cpp @@ -51,7 +51,7 @@ inline void va_end_(va_list& args) CODA_OSS_disable_warning_pop } -std::string str::Format(const char* format, ...) +std::string str::details::Format_(const char* format, ...) { va_list args; va_start(args, format); diff --git a/modules/c++/str/source/Manip.cpp b/modules/c++/str/source/Manip.cpp index f8dbce7db..87b06acdf 100644 --- a/modules/c++/str/source/Manip.cpp +++ b/modules/c++/str/source/Manip.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "gsl/gsl.h" @@ -40,7 +41,7 @@ namespace { -char transformCheck(int c, int (*transform)(int)) +inline char transformCheck(int c, int (*transform)(int)) { // Ensure the character can be represented // as an unsigned char or is 'EOF', as the @@ -56,12 +57,12 @@ char transformCheck(int c, int (*transform)(int)) } } -char tolowerCheck(char c) +inline char tolowerCheck(char c) { return transformCheck(c, tolower); } -char toupperCheck(char c) +inline char toupperCheck(char c) { return transformCheck(c, toupper); } @@ -239,9 +240,8 @@ bool isAlphanumeric(const std::string& s) bool isAsciiPrintable(const std::string& s) { - for (const auto& ch : s) + for (const auto& c : s) { - char c = ch; if (c < 32 || c > 126) return false; } @@ -290,24 +290,210 @@ std::vector split(const std::string& s, return vec; } -template -inline void transform(std::basic_string& s, Fn f) + +// Calling ::toupper() can be slow as the CRT might check for locales. +// Since we only have 256 values, a lookup table is very fast and doesn't +// use much memory. +static const auto& make_lookup(std::array& result, + char (*to)(char)) +{ + // For each of 256 values, record the corresponding tolower/toupper value; + // this makes converting very fast as no checking or arithmetic must be done. + for (size_t i = 0; i <= 0xff; i++) + { + const auto ch = to(static_cast(i)); + result[i] = static_cast(ch); + } + return result; +} + +template +static void do_lookup(std::basic_string& s, const std::array& lookup) +{ + for (auto& ch : s) + { + const auto i = static_cast(ch); + ch = static_cast(lookup[i]); + } +} + +void ascii_upper(std::string& s) +{ + static std::array lookup_; + static const auto& lookup = make_lookup(lookup_, toupperCheck); + do_lookup(s, lookup); +} + +void ascii_lower(std::string& s) +{ + static std::array lookup_; + static const auto& lookup = make_lookup(lookup_, tolowerCheck); + do_lookup(s, lookup); +} + +inline char to_w1252_upper_(char ch) +{ + if ((ch >= 'a') && (ch <= 'z')) + { + return ch ^ 0x20; // ('a' - 'A'); + } + + // See chart at: https://en.wikipedia.org/wiki/Windows-1252 + const auto u8 = static_cast(ch); + + constexpr uint8_t s_with_caron = 0x9a /* */; + constexpr uint8_t oe = 0x9c /* */; + constexpr uint8_t z_with_caron = 0x9e /* */; + if ((u8 == s_with_caron) || (u8 == oe) || (u8 == z_with_caron)) + { + return ch ^ 0x10; + } + + constexpr uint8_t a_with_grave = 0xe0 /* */; + constexpr uint8_t o_with_diaeresis = 0xf6 /* */; + if ((u8 >= a_with_grave) && (u8 <= o_with_diaeresis)) + { + return ch ^ 0x20; + } + // U+00F7 DIVISION SIGN + constexpr uint8_t o_with_slash = 0xf8 /* */; + constexpr uint8_t small_thorn = 0xfe /* */; + if ((u8 >= o_with_slash) && (u8 <= small_thorn)) + { + return ch ^ 0x20; + } + + constexpr uint8_t y_with_diaeresis = 0xff /* */; + if (u8 == y_with_diaeresis) + { + constexpr uint8_t Y_with_diaeresis = 0x9f /* */; + return Y_with_diaeresis; + } + + return ch; +} +str::Windows1252_T to_w1252_upper(str::Windows1252_T ch) +{ + const auto retval = to_w1252_upper_(static_cast(ch)); + return static_cast(retval); +} + +inline char to_w1252_lower_(char ch) +{ + if ((ch >= 'A') && (ch <= 'Z')) + { + return ch | 0x20; + } + + // See chart at: https://en.wikipedia.org/wiki/Windows-1252 + const auto u8 = static_cast(ch); + + constexpr uint8_t S_with_caron = 0x8a /* */; + constexpr uint8_t OE = 0x8c /* */; + constexpr uint8_t Z_with_caron = 0x8e /* */; + if ((u8 == S_with_caron) || (u8 == OE) || (u8 == Z_with_caron)) + { + return ch | 0x10; + } + + constexpr uint8_t Y_with_diaeresis = 0x9f /* */; + if (u8 == Y_with_diaeresis) + { + constexpr uint8_t y_with_diaeresis = 0xff /* */; + return y_with_diaeresis; + } + + constexpr uint8_t A_with_grave = 0xc0 /* */; + constexpr uint8_t O_with_diaeresis = 0xd6 /* */; + if ((u8 >= A_with_grave) && (u8 <= O_with_diaeresis)) + { + return ch | 0x20; + } + // U+00D7 MULTIPLICATION SIGN + constexpr uint8_t O_with_slash = 0xd8 /* */; + constexpr uint8_t capital_thorn = 0xde /* */; + if ((u8 >= O_with_slash) && (u8 <= capital_thorn)) + { + return ch | 0x20; + } + + return ch; +} +str::Windows1252_T to_w1252_lower(str::Windows1252_T ch) +{ + const auto retval = to_w1252_lower_(static_cast(ch)); + return static_cast(retval); +} + +static const auto& w1252_upper_lookup() +{ + static std::array lookup_; + static const auto& lookup = make_lookup(lookup_, to_w1252_upper_); + return lookup; +} +void w1252_upper(std::string& w1252) +{ + do_lookup(w1252, w1252_upper_lookup()); +} +void upper(str::W1252string& s) +{ + do_lookup(s, w1252_upper_lookup()); +} + +static const auto& w1252_lower_lookup() +{ + static std::array lookup_; + static const auto& lookup = make_lookup(lookup_, to_w1252_lower_); + return lookup; +} +void w1252_lower(std::string& w1252) +{ + do_lookup(w1252, w1252_lower_lookup()); +} +void lower(str::W1252string& s) +{ + do_lookup(s, w1252_lower_lookup()); +} + +// These routines are SLOW ... yes, they can be made faster +// but nobody needs that right now. +inline auto utf8_convert(str::W1252string& w1252, void (*convert)(str::W1252string&)) +{ + convert(w1252); // upper() or lower() for Windows-1252 + return to_u8string(w1252); +} +inline void utf8_convert(std::string& strUtf8, void (*convert)(str::W1252string&)) +{ + auto w1252 = to_w1252string(str::str(strUtf8)); + const auto utf8 = utf8_convert(w1252, convert); + strUtf8 = str::str(utf8); +} +void utf8_upper(std::string& strUtf8) +{ + utf8_convert(strUtf8, upper); +} +void utf8_lower(std::string& strUtf8) +{ + utf8_convert(strUtf8, lower); +} + +inline void utf8_convert(coda_oss::u8string& s, void (*convert)(str::W1252string&)) { - (void) std::transform(s.begin(), s.end(), s.begin(), f); + auto w1252 = to_w1252string(s); + s = utf8_convert(w1252, convert); } -void lower(std::string& s) +void lower(coda_oss::u8string& s) { - transform(s, tolowerCheck); + utf8_convert(s, lower); } -void upper(std::string& s) +void upper(coda_oss::u8string& s) { - transform(s, toupperCheck); + utf8_convert(s, upper); } void escapeForXML(std::string& str) { - // & needs to be first or else it'll mess up the other characters that we - // replace + // & needs to be first or else it'll mess up the other characters that we replace replaceAll(str, "&", "&"); replaceAll(str, "<", "<"); replaceAll(str, ">", ">"); diff --git a/modules/c++/str/tests/VersionTest.cpp b/modules/c++/str/tests/VersionTest.cpp index 6b2c00b6d..627696cdf 100644 --- a/modules/c++/str/tests/VersionTest.cpp +++ b/modules/c++/str/tests/VersionTest.cpp @@ -23,17 +23,15 @@ #include #include -#define FORMAT_FUNC str::Format - int main() { - std::cout << FORMAT_FUNC("Your version of str is %d.%d.%d\n", + std::cout << str::Format("Your version of str is %d.%d.%d\n", STR_MAJOR_VERSION, STR_MINOR_VERSION, STR_MICRO_VERSION); - std::cout << "Specialization for string test..." << std::endl; + std::cout << "Specialization for string test...\n"; std::string ok("This test passes"); std::cout << str::toType(ok) << std::endl; - std::cout << "Testing the trim function..." << std::endl; + std::cout << "Testing the trim function...\n"; std::string s = " test "; std::cout << "'" << s << "', length: " << s.length() << std::endl; str::trim(s); diff --git a/modules/c++/str/unittests/test_base_convert.cpp b/modules/c++/str/unittests/test_base_convert.cpp index 785cc327c..c2ecf4f36 100644 --- a/modules/c++/str/unittests/test_base_convert.cpp +++ b/modules/c++/str/unittests/test_base_convert.cpp @@ -64,9 +64,9 @@ TEST_CASE(testBadConvert) TEST_CASE(testEightBitIntToString) { - TEST_ASSERT_EQ(str::toString(static_cast(1)), "1"); - TEST_ASSERT_EQ(str::toString(static_cast(2)), "2"); - TEST_ASSERT_EQ(str::toString(static_cast(-2)), "-2"); + TEST_ASSERT_EQ(std::to_string(static_cast(1)), "1"); + TEST_ASSERT_EQ(std::to_string(static_cast(2)), "2"); + TEST_ASSERT_EQ(std::to_string(static_cast(-2)), "-2"); } TEST_CASE(testCharToString) @@ -78,25 +78,16 @@ TEST_CASE(testCharToString) template static constexpr std::u8string::value_type cast8(T ch) { - static_assert(sizeof(std::u8string::value_type) == sizeof(char), "sizeof(Char8_T) != sizeof(char)"); - return static_cast(ch); -} -template -static inline constexpr std::u32string::value_type U(TChar ch) -{ - return static_cast(ch); -} - -static auto from_windows1252(const std::string& w1252) -{ - return to_u8string(str::c_str(w1252), w1252.length()); + using u8ch_t = std::u8string::value_type; + static_assert(sizeof(u8ch_t) == sizeof(char), "sizeof(Char8_T) != sizeof(char)"); + return static_cast(ch); } TEST_CASE(test_string_to_u8string_ascii) { { const std::string input = "|\x00"; // ASCII, "|" - const auto actual = from_windows1252(input); + const auto actual = str::to_u8string(input); const std::u8string expected{cast8('|')}; // '\x00' is the end of the string in C/C++ TEST_ASSERT_EQ(actual, expected); } @@ -105,10 +96,10 @@ TEST_CASE(test_string_to_u8string_ascii) for (uint8_t ch = start_of_heading; ch <= delete_character; ch++) // ASCII { const std::string input { '|', static_cast(ch), '|'}; - const auto actual = from_windows1252(input); + const auto actual = str::to_u8string(input); const std::u8string expected8{cast8('|'), cast8(ch), cast8('|')}; TEST_ASSERT_EQ(actual, expected8); - const std::u32string expected{U'|', U(ch), U'|'}; + const std::u32string expected{U'|', ch, U'|'}; test_assert_eq(testName, actual, expected); } } @@ -130,7 +121,7 @@ TEST_CASE(test_string_to_u8string_windows_1252) // Windows-1252 only characters must be mapped to UTF-8 { const std::string input = "|\x80|"; // Windows-1252, "||" - const auto actual = from_windows1252(input); + const auto actual = str::to_u8string(input); const std::u8string expected8{cast8('|'), cast8('\xE2'), cast8('\x82'), cast8('\xAC'), cast8('|')}; // UTF-8, "||" TEST_ASSERT_EQ(actual, expected8); const std::u32string expected{U"|\u20AC|"}; // UTF-32, "||" @@ -138,7 +129,7 @@ TEST_CASE(test_string_to_u8string_windows_1252) } { const std::string input = "|\x9F|"; // Windows-1252, "||" - const auto actual = from_windows1252(input); + const auto actual = str::to_u8string(input); const std::u8string expected8{cast8('|'), cast8('\xC5'), cast8('\xB8'), cast8('|')}; // UTF-8, "||" TEST_ASSERT_EQ(actual, expected8); const std::u32string expected{U"|\u0178|"}; // UTF-32, "||" @@ -149,7 +140,7 @@ TEST_CASE(test_string_to_u8string_windows_1252) for (const auto& ch : undefined) { const std::string input{'|', ch, '|'}; - const auto actual = from_windows1252(input); + const auto actual = str::to_u8string(input); TEST_ASSERT_TRUE(!actual.empty()); //const std::u8string expected8{cast8('|'), cast8('\xEF'), cast8('\xBF'), cast8('\xBD'), cast8('|')}; // UTF-8, "||" const std::u8string expected8{cast8('|'), cast8(194), cast8(ch), cast8('|')}; @@ -217,7 +208,7 @@ TEST_CASE(test_string_to_u8string_iso8859_1) const std::string input_ { '|', static_cast(ch), '|'}; const auto input(str::str(input_)); const auto actual = to_u8string(input); - const std::u32string expected{U'|', U(ch), U'|'}; + const std::u32string expected{U'|', ch, U'|'}; test_assert_eq(testName, actual, expected); TEST_ASSERT(str::to_u8string(input) == actual); @@ -225,21 +216,18 @@ TEST_CASE(test_string_to_u8string_iso8859_1) } } -template -static void test_change_case_(const std::string& testName, const TString& lower, const TString& upper) +template +static void test_change_case_(const std::string& testName, + const std::basic_string& lower, const std::basic_string& upper) { - auto s = upper; - str::lower(s); + auto s = str::lower(upper); TEST_ASSERT(s == lower); - s = lower; - str::upper(s); + s = str::upper(lower); TEST_ASSERT(s == upper); - s = upper; - str::upper(s); + s = str::upper(upper); TEST_ASSERT(s == upper); - s = lower; - str::lower(s); + s = str::lower(lower); TEST_ASSERT(s == lower); } TEST_CASE(test_change_case) @@ -252,14 +240,16 @@ TEST_CASE(test_change_case) //const std::wstring abc_w = L"abc"; //test_change_case_(testName, abc_w, ABC_w); - //// Yes, this can really come up, "non classifi" is French (Canadian) for "unclassified". - //const std::string DEF_1252{'D', '\xc9', 'F'}; // "DF" Windows-1252 - //const auto DEF8 = from_windows1252(DEF_1252); + // Yes, this can really come up, "non classifi" is French (Canadian) for "unclassified". + const std::string DEF_1252_{'D', '\xc9', 'F'}; // "DF" Windows-1252 + const auto DEF_1252 = str::str(DEF_1252_); + const auto DEF8 = str::to_u8string(DEF_1252); - //const std::string def_1252{'d', '\xe9', 'f'}; // "df" Windows-1252 - //const auto def8 = from_windows1252(def_1252); + const std::string def_1252_{'d', '\xe9', 'f'}; // "df" Windows-1252 + const auto def_1252 = str::str(def_1252_); + const auto def8 = str::to_u8string(def_1252); - ////test_change_case_(testName, def, DEF); + //test_change_case_(testName, def8, DEF8); //test_change_case_(testName, def_1252, DEF_1252); } @@ -276,34 +266,39 @@ static const str::W1252string& classificationText_w1252() return retval; } + static auto toString(const coda_oss::u8string& s) + { + return str::to_native(s); + } + // UTF-16 on Windows, UTF-32 on Linux -static const wchar_t* classificationText_wide_() { return L"A\xc9IOU"; } // UTF-8 "AIOU" -static std::u16string classificationText_u16() { return u"A\xc9IOU"; } // UTF-16 "AIOU" -static std::u32string classificationText_u32() { return U"A\xc9IOU"; } // UTF-32 "AIOU" +static const wchar_t* classificationText_wide_() { return L"A\x00c9IOU"; } // "wide characters" "AIOU" +static std::u16string classificationText_u16() { return u"A\u00c9IOU"; } // UTF-16 "AIOU" +static std::u32string classificationText_u32() { return U"A\u00c9IOU"; } // UTF-32 "AIOU" static std::string classificationText_platform() { return - sys::Platform == sys::PlatformType::Linux ? str::toString(classificationText_u8()) : str::toString(classificationText_w1252()); } + sys::Platform == sys::PlatformType::Linux ? toString(classificationText_u8()) : str::testing::to_string(classificationText_w1252()); } TEST_CASE(test_u8string_to_string) { - auto actual = str::toString(classificationText_u8()); + auto actual = toString(classificationText_u8()); TEST_ASSERT_EQ(classificationText_platform(), actual); - actual = str::toString(classificationText_w1252()); + actual = str::testing::to_string(classificationText_w1252()); TEST_ASSERT_EQ(classificationText_platform(), actual); } -static auto to_w1252string(const std::wstring& s) +static auto w1252FromNative(const std::wstring& s) { - return str::to_w1252string(str::u8FromWString(s)); + return str::to_w1252string(str::u8FromNative(s)); } -static auto to_u16string(const str::W1252string& s) +static auto toWString(const str::W1252string& s) { - return str::to_u16string(s.c_str(), s.length()); + return str::testing::to_wstring(s); } -static auto to_u32string(const str::W1252string& s) +static auto toWString(const coda_oss::u8string& s) { - return str::to_u32string(s.c_str(), s.length()); + return str::details::to_wstring(s); } TEST_CASE(test_u8string_to_u16string) @@ -316,12 +311,12 @@ TEST_CASE(test_u8string_to_u16string) #endif const auto u8 = classificationText_u8(); - TEST_ASSERT(str::u8FromWString(wide) == u8); - TEST_ASSERT(wide == str::toWString(u8)); + TEST_ASSERT(str::u8FromNative(wide) == u8); + TEST_ASSERT(wide == toWString(u8)); const auto w1252 = str::c_str(classificationText_w1252()); - TEST_ASSERT(to_w1252string(wide) == w1252); - TEST_ASSERT(wide == str::toWString(w1252)); + TEST_ASSERT(w1252FromNative(wide) == w1252); + TEST_ASSERT(wide == toWString(w1252)); TEST_ASSERT(classificationText_u16() == actual); // _EQ wants to do toString() TEST_ASSERT(classificationText_u16() == to_u16string(w1252)); // _EQ wants to do toString() @@ -337,37 +332,28 @@ TEST_CASE(test_u8string_to_u32string) const std::wstring wide(classificationText_wide_()); const auto u8 = classificationText_u8(); - TEST_ASSERT(str::u8FromWString(wide) == u8); - TEST_ASSERT(wide == str::toWString(u8)); + TEST_ASSERT(str::u8FromNative(wide) == u8); + TEST_ASSERT(wide == toWString(u8)); const auto w1252 = str::c_str(classificationText_w1252()); - TEST_ASSERT(to_w1252string(wide) == w1252); - TEST_ASSERT(wide == str::toWString(w1252)); + TEST_ASSERT(w1252FromNative(wide) == w1252); + TEST_ASSERT(wide == toWString(w1252)); TEST_ASSERT(classificationText_u32() == actual); // _EQ wants to do toString() TEST_ASSERT(classificationText_u32() == to_u32string(w1252)); // _EQ wants to do toString() } -static auto as_windows1252(const coda_oss::u8string& s) -{ - const auto w1252 = str::to_w1252string(s.c_str(), s.length()); - return str::toString(w1252); -} -static auto from_utf8(const std::string& utf8) -{ - return str::str(utf8); -} -static auto as_utf8(const coda_oss::u8string& s) +static auto toWString(const std::u16string& s) { - return str::str(s); + return toWString(str::to_u8string(s)); } -static auto toWString(const std::u16string& s) +static auto toWString(const std::string& s) { - return str::toWString(str::to_u8string(s)); + return str::details::to_wstring(s); } static auto toString(const std::u16string& s) { - return str::toString(str::to_u8string(s)); + return str::details::to_string(str::to_u8string(s)); } static void test_wide_(const std::string& testName, const char* pStr, std::u16string::const_pointer pUtf16, @@ -379,14 +365,14 @@ static void test_wide_(const std::string& testName, const char* pStr, std::u16st #if _WIN32 // Since we're using UTF-16, on Windows that can be cast to wchar_t - auto pWide = str::cast(pUtf16); + const auto wide = str::make_string(pUtf16); const _bstr_t str(pStr); const std::wstring std_wstr(static_cast(str)); // Windows-1252 -> UTF-16 TEST_ASSERT(wstring == std_wstr); - TEST_ASSERT(std_wstr == pWide); + TEST_ASSERT(std_wstr == wide); - const _bstr_t wide_str(pWide); + const _bstr_t wide_str(wide.c_str()); const std::string std_str(static_cast(wide_str)); // UTF-16 -> Windows-1252 TEST_ASSERT_EQ(native, std_str); TEST_ASSERT_EQ(std_str, pStr); @@ -399,18 +385,19 @@ static void test_wide_(const std::string& testName, const char* pStr, std::u16st static void test_Windows1252_ascii(const std::string& testName, const char* pStr, std::u16string::const_pointer pUtf16) { // For both UTF-8 and Windows-1252, ASCII is the same (they only differ for 0x80-0xff). - const auto u8 = as_utf8(from_utf8(pStr)); + const auto u8 = str::str(str::to_u8string(pStr)); TEST_ASSERT_EQ(pStr, u8); // native() is the same on all platforms/encodings for ASCII { - const auto w1252 = as_windows1252(from_windows1252(pStr)); - TEST_ASSERT_EQ(pStr, w1252); // native() is the same on all platforms/encodings for ASCII + const auto w1252 = str::make_string(pStr); + const auto str1252 = str::testing::to_string(w1252); + TEST_ASSERT_EQ(pStr, str1252); // native() is the same on all platforms/encodings for ASCII } - const auto u16 = str::to_u16string(str::u8FromString(pStr)); + const auto u16 = str::to_u16string(str::u8FromNative(pStr)); TEST_ASSERT(u16 == pUtf16); - auto wstring = str::toWString(pStr); + auto wstring = toWString(pStr); std::string native = pStr; - auto w1252 = str::cast(pStr); + auto w1252 = str::make_string(pStr); test_wide_(testName, pStr, pUtf16, wstring, native, w1252); native = toString(pUtf16); @@ -442,13 +429,17 @@ static auto to_w1252string(const std::u16string& s) { return str::to_w1252string(str::to_u8string(s)); } +inline static auto toString(const std::wstring& s) +{ + return str::details::to_string(s); +} static void test_Windows1252_(const std::string& testName, const char* pStr, std::u16string::const_pointer pUtf16) { - const auto u16 = str::to_u16string(from_windows1252(pStr)); + const auto u16 = str::to_u16string(str::to_u8string(pStr)); TEST_ASSERT(u16 == pUtf16); - auto wstring = str::toWString(from_windows1252(pStr)); - auto s = str::toString(from_windows1252(pStr)); + auto wstring = toWString(str::to_u8string(pStr)); + auto s = toString(str::to_u8string(pStr)); auto w1252 = str::make_string(pStr); test_wide_(testName, pStr, pUtf16, wstring, s, w1252); @@ -550,7 +541,7 @@ TEST_CASE(test_Windows1252) { const std::string expected(1, ch.first); const std::wstring input(1, ch.second); // `std::wstring` is UTF-16 on Windows - const auto actual = str::toString(input); + const auto actual = toString(input); TEST_ASSERT_EQ(expected, actual); } #endif @@ -572,14 +563,14 @@ static void test_Encodeding_(const std::string& testName, const coda_oss::u8stri TEST_ASSERT_EQ(utf_8_view, expected); TEST_ASSERT_EQ(iso8859_1_view, expected); } -TEST_CASE(test_Encodeding) +TEST_CASE(test_Encoding) { - const auto utf_8 = str::toString(classificationText_u8()); - const auto iso8859_1 = str::toString(classificationText_w1252()); + const auto utf_8 = toString(classificationText_u8()); + const auto iso8859_1 = str::testing::to_string(classificationText_w1252()); const auto utf_8_u8 = classificationText_u8(); const auto iso8859_1_u8 = str::to_u8string(classificationText_w1252()); - const auto utf_8_view = as_utf8(classificationText_u8()); - const auto iso8859_1_view = as_utf8(from_windows1252(str::c_str(classificationText_w1252()))); + const auto utf_8_view = str::str(classificationText_u8()); + const auto iso8859_1_view = str::str(str::to_u8string(classificationText_w1252())); test_Encodeding_(testName, classificationText_u8(), utf_8, iso8859_1, @@ -606,5 +597,5 @@ TEST_MAIN( TEST_CHECK(test_ASCII); TEST_CHECK(test_Windows1252_WIN32); TEST_CHECK(test_Windows1252); - TEST_CHECK(test_Encodeding); + TEST_CHECK(test_Encoding); ) diff --git a/modules/c++/str/unittests/test_str.cpp b/modules/c++/str/unittests/test_str.cpp index 8fd60b90d..eb4821608 100644 --- a/modules/c++/str/unittests/test_str.cpp +++ b/modules/c++/str/unittests/test_str.cpp @@ -21,6 +21,7 @@ */ #include // std::ignore +#include #include #include @@ -56,16 +57,78 @@ TEST_CASE(testData) TEST_CASE(testUpper) { - std::string s = "test-something1"; + const std::string s_ = "test-something1"; + std::string s = s_; + TEST_ASSERT(str::eq(s, "TEST-SOMETHING1")); str::upper( s); TEST_ASSERT_EQ(s, "TEST-SOMETHING1"); + + //#if _WIN32 + //s = ""; + //str::w1252_upper(s); + //TEST_ASSERT_EQ(s, ""); + //#endif +} + +TEST_CASE(test_toupper) +{ + for (uint16_t i = 0x20; i <= 0xff; i++) // uint16_t to avoid wrap-around + { + const auto w1252 = static_cast(i); + const auto w1252_upper = str::to_w1252_upper(w1252); + + const auto w1252_lower = w1252 == w1252_upper ? w1252 : str::to_w1252_lower(w1252_upper); // round-trip + TEST_ASSERT_EQ(static_cast(w1252), static_cast(w1252_lower)); + + if (i <= 0x7f) // ASCII + { + const auto ch = static_cast(i); + const auto upper = toupper(ch); + TEST_ASSERT_EQ(static_cast(upper), static_cast(w1252_upper)); + + const auto lower = ch == upper ? ch : tolower(upper); // round-trip + TEST_ASSERT_EQ(ch, lower); + TEST_ASSERT_EQ(static_cast(lower), static_cast(w1252_lower)); + } + } } TEST_CASE(testLower) { - std::string s = "TEST1"; - str::lower( s); + const std::string s_ = "TEST1"; + std::string s = s_; + TEST_ASSERT(str::eq(s, "test1")); + str::lower(s); TEST_ASSERT_EQ(s, "test1"); + + //#if _WIN32 + //s = "[]"; + //str::w1252_lower(s); + //TEST_ASSERT_EQ(s, "[]"); + //#endif +} + +TEST_CASE(test_tolower) +{ + for (uint16_t i = 0x20; i <= 0xff; i++) // uint16_t to avoid wrap-around + { + const auto w1252 = static_cast(i); + const auto w1252_lower = str::to_w1252_lower(w1252); + + const auto w1252_upper = w1252 == w1252_lower ? w1252 : str::to_w1252_upper(w1252_lower); // round-trip + TEST_ASSERT_EQ(static_cast(w1252), static_cast(w1252_upper)); + + if (i <= 0x7f) // ASCII + { + const auto ch = static_cast(i); + const auto lower = tolower(ch); + TEST_ASSERT_EQ(static_cast(lower), static_cast(w1252_lower)); + + const auto upper = ch == lower ? ch : toupper(lower); // round-trip + TEST_ASSERT_EQ(ch, upper); + TEST_ASSERT_EQ(static_cast(upper), static_cast(w1252_upper)); + } + } } TEST_CASE(test_eq_ne) @@ -125,9 +188,9 @@ TEST_CASE(testSplit) { std::string s = "space delimited values are the best!"; std::vector parts = str::split(s, " "); - TEST_ASSERT_EQ(parts.size(), static_cast(6)); + TEST_ASSERT_EQ(std::ssize(parts), 6); parts = str::split(s, " ", 3); - TEST_ASSERT_EQ(parts.size(), static_cast(3)); + TEST_ASSERT_EQ(std::ssize(parts), 3); TEST_ASSERT_EQ(parts[2], "values are the best!"); } @@ -308,7 +371,9 @@ TEST_MAIN( TEST_CHECK(testTrim); TEST_CHECK(testData); TEST_CHECK(testUpper); + TEST_CHECK(test_toupper); TEST_CHECK(testLower); + TEST_CHECK(test_tolower); TEST_CHECK(test_eq_ne); TEST_CHECK(testReplace); TEST_CHECK(testReplaceAllInfinite); diff --git a/modules/c++/sys/include/sys/AbstractOS.h b/modules/c++/sys/include/sys/AbstractOS.h index 1b040790e..efd80de08 100644 --- a/modules/c++/sys/include/sys/AbstractOS.h +++ b/modules/c++/sys/include/sys/AbstractOS.h @@ -63,6 +63,20 @@ enum class SIMDInstructionSet AVX512F, // https://en.wikipedia.org/wiki/AVX-512 }; +constexpr auto getSIMDInstructionSet() { return SIMDInstructionSet:: + // https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 + + #if __AVX512F__ + AVX512F + #elif __AVX2__ + AVX2 + #elif _M_X64 /*MSVC*/ || __SSE2__ /*GCC*/ + SSE2 + #else + #error "Can't determine SIMDInstructionSet'" + #endif +; } + /*! * \class AbstractOS * \brief Interface for system independent function calls diff --git a/modules/c++/sys/include/sys/Conf.h b/modules/c++/sys/include/sys/Conf.h index 6dd45ea28..3469b69cf 100644 --- a/modules/c++/sys/include/sys/Conf.h +++ b/modules/c++/sys/include/sys/Conf.h @@ -217,9 +217,7 @@ namespace sys #error "Don't know how to implement alignedAlloc()." #endif if (!p) - throw except::Exception(Ctxt( - "Aligned allocation failure of size [" + - str::toString(size) + "] bytes")); + throw except::Exception(Ctxt("Aligned allocation failure of size [" + std::to_string(size) + "] bytes")); return p; } diff --git a/modules/c++/sys/include/sys/DLL.h b/modules/c++/sys/include/sys/DLL.h index 28fbb6be5..c384a461b 100644 --- a/modules/c++/sys/include/sys/DLL.h +++ b/modules/c++/sys/include/sys/DLL.h @@ -20,7 +20,7 @@ * */ - +#pragma once #ifndef __SYS_DLL_H__ #define __SYS_DLL_H__ @@ -52,6 +52,7 @@ typedef void* DLL_FUNCTION_PTR; #include "except/Exception.h" #include "sys/Err.h" +#include "config/Exports.h" namespace sys @@ -124,7 +125,7 @@ struct DLLException : public except::Exception */ -struct DLL +struct CODA_OSS_API DLL { /*! * Construct a library object, but dont populate or load it diff --git a/modules/c++/sys/include/sys/FileFinder.h b/modules/c++/sys/include/sys/FileFinder.h index 0485de3c8..e60ec8553 100644 --- a/modules/c++/sys/include/sys/FileFinder.h +++ b/modules/c++/sys/include/sys/FileFinder.h @@ -20,6 +20,7 @@ * */ +#pragma once #ifndef __SYS_FILE_FINDER_H__ #define __SYS_FILE_FINDER_H__ @@ -37,7 +38,7 @@ namespace sys /** * Predicate interface for all entries */ -struct FilePredicate +struct CODA_OSS_API FilePredicate { using argument_type = std::string; using result_type = bool; @@ -58,7 +59,7 @@ struct ExistsPredicate : FilePredicate /** * Predicate that matches files only (no directories) */ -struct FileOnlyPredicate: public FilePredicate +struct CODA_OSS_API FileOnlyPredicate : public FilePredicate { virtual ~FileOnlyPredicate() = default; virtual bool operator()(const std::string& entry) const override; @@ -147,7 +148,7 @@ struct LogicalPredicate : public FilePredicate * The FileFinder class allows you to search for * files/directories in a clean way. */ -struct FileFinder final +struct CODA_OSS_API FileFinder final { FileFinder() = default; ~FileFinder() = default; @@ -167,7 +168,7 @@ struct FileFinder final // until either the file is found or we stop at a ".git" directory. // // This (obviously) might take a while, so consider whether the result should be cached. -coda_oss::filesystem::path findFirstFile(const coda_oss::filesystem::path& startingDirectory, const coda_oss::filesystem::path& filename); +CODA_OSS_API coda_oss::filesystem::path findFirstFile(const coda_oss::filesystem::path& startingDirectory, const coda_oss::filesystem::path& filename); coda_oss::filesystem::path findFirstDirectory(const coda_oss::filesystem::path& startingDirectory, const coda_oss::filesystem::path& dir); // This is here most to avoid creating a new module for a few utility routines @@ -175,11 +176,11 @@ namespace test // i.e., sys::test { // Try to find the specified "root" directory starting at the given path. // Used by unittest to find sample files. - coda_oss::filesystem::path findRootDirectory(const coda_oss::filesystem::path& p, const std::string& rootName, + CODA_OSS_API coda_oss::filesystem::path findRootDirectory(const coda_oss::filesystem::path& p, const std::string& rootName, std::function isRoot); - coda_oss::filesystem::path findCMakeBuildRoot(const coda_oss::filesystem::path& p); - bool isCMakeBuild(const coda_oss::filesystem::path& p); + CODA_OSS_API coda_oss::filesystem::path findCMakeBuildRoot(const coda_oss::filesystem::path& p); + bool CODA_OSS_API isCMakeBuild(const coda_oss::filesystem::path& p); coda_oss::filesystem::path findCMakeInstallRoot(const coda_oss::filesystem::path& p); bool isCMakeInstall(const coda_oss::filesystem::path& p); diff --git a/modules/c++/sys/include/sys/Path.h b/modules/c++/sys/include/sys/Path.h index d7d950202..cb1ba14c8 100644 --- a/modules/c++/sys/include/sys/Path.h +++ b/modules/c++/sys/include/sys/Path.h @@ -27,13 +27,15 @@ #include #include #include +#include #include "config/Exports.h" - #include +#include "coda_oss/span.h" #include "sys/OS.h" #include "sys/filesystem.h" +#include "sys/Span.h" /*! @@ -295,6 +297,16 @@ class CODA_OSS_API Path std::ostream& operator<<(std::ostream& os, const sys::Path& path); std::istream& operator>>(std::istream& os, sys::Path& path); + +// Convert between collections of paths as strings and coda_oss::filesystem::path +CODA_OSS_API std::vector convertPaths(coda_oss::span); +CODA_OSS_API std::vector convertPaths(coda_oss::span); +template +inline auto convertPaths(const std::vector& paths) +{ + return convertPaths(make_span(paths)); +} + } #endif // CODA_OSS_sys_Path_h_INCLUDED_ diff --git a/modules/c++/sys/include/sys/ThreadInterface.h b/modules/c++/sys/include/sys/ThreadInterface.h index e536fe48e..cefbf8dcc 100644 --- a/modules/c++/sys/include/sys/ThreadInterface.h +++ b/modules/c++/sys/include/sys/ThreadInterface.h @@ -132,7 +132,7 @@ struct CODA_OSS_API ThreadInterface : public Runnable // of nasty issues that could pop up (execution in freed memory, etc). if (isRunning()) { - std::cerr << Ctxt(FmtX("Thread object [%s] destructed before " \ + std::cerr << Ctxt(str::Format("Thread object [%s] destructed before " \ "thread terminated, aborting program.", getName().c_str())) << std::endl; abort(); diff --git a/modules/c++/sys/include/sys/sys_filesystem.h b/modules/c++/sys/include/sys/sys_filesystem.h index 59df476a5..3cbab0837 100644 --- a/modules/c++/sys/include/sys/sys_filesystem.h +++ b/modules/c++/sys/include/sys/sys_filesystem.h @@ -79,6 +79,7 @@ struct CODA_OSS_API path final // N.B. this is an INCOMPLETE and NON-STANDARD im { *this = source; } + ~path() = default; path& operator=(const path&) = default; path& operator=(path&&) = default; diff --git a/modules/c++/sys/source/AbstractOS.cpp b/modules/c++/sys/source/AbstractOS.cpp index d1cd33306..ebe072ff7 100644 --- a/modules/c++/sys/source/AbstractOS.cpp +++ b/modules/c++/sys/source/AbstractOS.cpp @@ -86,29 +86,14 @@ AbstractOS::search(const std::vector& searchPaths, return elementsFound; } -inline auto convert(const std::vector& paths) -{ - std::vector retval; - std::transform(paths.begin(), paths.end(), std::back_inserter(retval), - [](const fs::path& p) { return p.string(); }); - return retval; -} -inline auto convert(const std::vector& paths) -{ - std::vector retval; - std::transform(paths.begin(), paths.end(), std::back_inserter(retval), - [](const auto& p) { return p; }); - return retval; -} - std::vector AbstractOS::search( const std::vector& searchPaths, const std::string& fragment, const std::string& extension, bool recursive) const { - const auto results = search(convert(searchPaths), fragment, extension, recursive); - return convert(results); + const auto results = search(convertPaths(searchPaths), fragment, extension, recursive); + return convertPaths(results); } void AbstractOS::remove(const std::string& path) const @@ -288,19 +273,17 @@ void AbstractOS::appendEnv(const std::string& envVar, const std::vector(std::difftime(std::time(nullptr), start)); - return str::toString(diff); + return std::to_string(diff); } static std::string getSpecialEnv_SECONDS(const AbstractOS&, const std::string& envVar) { // https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html // "This variable expands to the number of seconds since the shell was started. ..." assert(envVar == "SECONDS"); - #if _MSC_VER - UNREFERENCED_PARAMETER(envVar); - #endif + CODA_OSS_mark_symbol_unused(envVar); return getSpecialEnv_SECONDS_(); } @@ -475,7 +452,7 @@ std::string AbstractOS::getSpecialEnv(const std::string& envVar) const if (envVar == "EPOCHSECONDS") { - return str::toString(sys::DateTime::getEpochSeconds()); + return std::to_string(sys::DateTime::getEpochSeconds()); } if (envVar == "OSTYPE") diff --git a/modules/c++/sys/source/CppUnitTestAssert_.cpp_ b/modules/c++/sys/source/CppUnitTestAssert_.cpp_ index 072d66db9..03f941aea 100644 --- a/modules/c++/sys/source/CppUnitTestAssert_.cpp_ +++ b/modules/c++/sys/source/CppUnitTestAssert_.cpp_ @@ -35,5 +35,5 @@ void test::Assert::FailOnCondition(bool condition, const unsigned short* message std::wstring GetAssertMessage(bool equality, const std::wstring& expected, const std::wstring& actual, const wchar_t *message); // declare caller std::wstring test::Assert::GetAssertMessage(bool equality, const std::string& expected, const std::string& actual, const wchar_t *message) { - return ::GetAssertMessage(equality, str::toWString(expected), str::toWString(actual), message); // and call! + return ::GetAssertMessage(equality, str::details::to_wstring(expected), str::details::to_wstring(actual), message); // and call! } diff --git a/modules/c++/sys/source/DLLWin32.cpp b/modules/c++/sys/source/DLLWin32.cpp index 466f7d295..6fc96611f 100644 --- a/modules/c++/sys/source/DLLWin32.cpp +++ b/modules/c++/sys/source/DLLWin32.cpp @@ -45,7 +45,7 @@ void sys::DLL::load(const std::string& libName) // Now we check the return value if (!mLib) - throw sys::DLLException(FmtX("Failed to load() DLL: %s", + throw sys::DLLException(str::Format("Failed to load() DLL: %s", mLibName.c_str() ) ); } @@ -75,7 +75,7 @@ retrieve(const std::string& functionName) // Now we check the ptr value if (ptr == nullptr) - throw sys::DLLException(FmtX("Failed to load function: %s", + throw sys::DLLException(str::Format("Failed to load function: %s", functionName.c_str())); return ptr; } diff --git a/modules/c++/sys/source/DateTime.cpp b/modules/c++/sys/source/DateTime.cpp index a79b9bb8c..0679aed62 100644 --- a/modules/c++/sys/source/DateTime.cpp +++ b/modules/c++/sys/source/DateTime.cpp @@ -104,9 +104,7 @@ char* strptime(const char *buf, const char *fmt, struct tm& tm, double& millis) { bc = *bp++; if (bc != fc) - throw except::Exception(Ctxt( - "Value does not match format (" + str::toString(fc) + - "): " + str::toString(bc))); + throw except::Exception(Ctxt("Value does not match format (" + str::toString(fc) + "): " + str::toString(bc))); continue; } @@ -171,15 +169,13 @@ char* strptime(const char *buf, const char *fmt, struct tm& tm, double& millis) // Full name. len = DAY[i].size(); std::string day(bp, len); - str::lower(day); - if (day == DAY[i]) + if (str::eq(day, DAY[i])) break; // Abbreviated name. len = AB_DAY[i].size(); day = std::string(bp, len); - str::lower(day); - if (day == AB_DAY[i]) + if (str::eq(day, AB_DAY[i])) break; } @@ -204,15 +200,13 @@ char* strptime(const char *buf, const char *fmt, struct tm& tm, double& millis) // Full name. len = MONTH[i].size(); std::string month(bp, len); - str::lower(month); - if (month == MONTH[i]) + if (str::eq(month, MONTH[i])) break; // Abbreviated name. len = AB_MONTH[i].size(); month = std::string(bp, len); - str::lower(month); - if (month == AB_MONTH[i]) + if (str::eq(month, AB_MONTH[i])) break; } @@ -316,7 +310,7 @@ char* strptime(const char *buf, const char *fmt, struct tm& tm, double& millis) case 'Y': // The year. i = TM_YEAR_BASE; if (!(conv_num(bp, i, 0, 9999))) - throw except::Exception(Ctxt("Invalid year: " + str::toString(i))); + throw except::Exception(Ctxt("Invalid year: " + std::to_string(i))); tm.tm_year = i - TM_YEAR_BASE; break; @@ -469,9 +463,7 @@ std::string sys::DateTime::dayOfWeekToStringAbbr(int dayOfWeek) int sys::DateTime::monthToValue(const std::string& month) { - std::string m = month; - str::lower(m); - + const auto m = str::lower(month); if (str::startsWith(m, "jan")) return 1; else if (str::startsWith(m, "feb")) @@ -503,9 +495,7 @@ int sys::DateTime::monthToValue(const std::string& month) int sys::DateTime::dayOfWeekToValue(const std::string& dayOfWeek) { - std::string d = dayOfWeek; - str::lower(d); - + const auto d = str::lower(dayOfWeek); if (str::startsWith(d, "sun")) return 1; else if (str::startsWith(d, "mon")) diff --git a/modules/c++/sys/source/FileFinder.cpp b/modules/c++/sys/source/FileFinder.cpp index b33cc47c4..7edf1a512 100644 --- a/modules/c++/sys/source/FileFinder.cpp +++ b/modules/c++/sys/source/FileFinder.cpp @@ -56,12 +56,8 @@ bool sys::FragmentPredicate::operator()(const std::string& entry) const { if (mIgnoreCase) { - std::string base = entry; - str::lower(base); - - std::string match = mFragment; - str::lower(match); - + const auto base = str::lower(entry); + const auto match = str::lower(mFragment); return str::contains(base, match); } else @@ -80,13 +76,10 @@ bool sys::ExtensionPredicate::operator()(const std::string& filename) const if (!sys::FileOnlyPredicate::operator()(filename)) return false; - std::string ext = sys::Path::splitExt(filename).second; + const std::string ext = sys::Path::splitExt(filename).second; if (mIgnoreCase) { - std::string matchExt = mExt; - str::lower(matchExt); - str::lower(ext); - return ext == matchExt; + return str::eq(ext, mExt); } else return ext == mExt; diff --git a/modules/c++/sys/source/FileUnix.cpp b/modules/c++/sys/source/FileUnix.cpp index e603835a3..07d6c5ff9 100644 --- a/modules/c++/sys/source/FileUnix.cpp +++ b/modules/c++/sys/source/FileUnix.cpp @@ -43,7 +43,7 @@ void sys::File::create(const std::string& str, int accessFlags, if (mHandle < 0) { throw sys::SystemException(Ctxt( - FmtX("Error opening file [%d]: [%s]", mHandle, str.c_str()))); + str::Format("Error opening file [%d]: [%s]", mHandle, str.c_str()))); } } diff --git a/modules/c++/sys/source/FileWin32.cpp b/modules/c++/sys/source/FileWin32.cpp index 5e2f2b23d..7ab87bb47 100644 --- a/modules/c++/sys/source/FileWin32.cpp +++ b/modules/c++/sys/source/FileWin32.cpp @@ -58,8 +58,7 @@ void sys::File::create(const std::string& str, create(std::nothrow, str, accessFlags, creationFlags); if (mHandle == INVALID_HANDLE_VALUE) { - throw sys::SystemException( - Ctxt(FmtX("Error opening file: [%s]", str.c_str()))); + throw sys::SystemException(Ctxt(str::Format("Error opening file: [%s]", str))); } } @@ -141,7 +140,7 @@ sys::Off_T sys::File::seekTo(sys::Off_T offset, int whence) if (SetFilePointerEx(mHandle, largeInt, &newFilePointer, dwMoveMethod) == 0) { const auto dwLastError = GetLastError(); - throw sys::SystemException(Ctxt("SetFilePointer failed: GetLastError() = " + str::toString(dwLastError))); + throw sys::SystemException(Ctxt("SetFilePointer failed: GetLastError() = " + std::to_string(dwLastError))); } return static_cast(newFilePointer.QuadPart); @@ -169,8 +168,7 @@ sys::Off_T sys::File::lastModifiedTime() return (sys::Off_T)stInMillis; } throw sys::SystemException(Ctxt( - FmtX("Error getting last modified time for path %s", - mPath.c_str()))); + str::Format("Error getting last modified time for path %s", mPath))); } void sys::File::flush() diff --git a/modules/c++/sys/source/OSUnix.cpp b/modules/c++/sys/source/OSUnix.cpp index e561186f5..9a3cb61b9 100644 --- a/modules/c++/sys/source/OSUnix.cpp +++ b/modules/c++/sys/source/OSUnix.cpp @@ -122,7 +122,7 @@ std::set get_unique_thread_siblings() std::ostringstream msg; msg << "Unable to open thread siblings file " << tsPath.getPath(); - throw except::Exception(Ctxt(msg.str())); + throw except::Exception(Ctxt(msg)); } std::string tsContents; @@ -143,8 +143,10 @@ std::string sys::OSUnix::getPlatformName() const if (uname(&name) == -1) throw sys::SystemException("Uname failed"); - return str::Format("%s (%s): %s [build: %s]", name.sysname, name.machine, - name.release, name.version); + std::string retval = name.sysname; + retval += str::Format(" (%s): %s", name.machine, name.release); + retval += str::Format(" [build: %s]", name.version); + return retval; } std::string sys::OSUnix::getNodeName() const @@ -174,7 +176,7 @@ void sys::OSUnix::removeFile(const std::string& pathname) const oss << "Failure removing file [" << pathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } @@ -187,7 +189,7 @@ void sys::OSUnix::removeDirectory(const std::string& pathname) const oss << "Failure removing directory [" << pathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } @@ -461,7 +463,7 @@ void sys::OSUnix::removeSymlink(const std::string& symlinkPathname) const oss << "Failure removing symlink [" << symlinkPathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } diff --git a/modules/c++/sys/source/OSWin32.cpp b/modules/c++/sys/source/OSWin32.cpp index 57137ac69..a9aed80de 100644 --- a/modules/c++/sys/source/OSWin32.cpp +++ b/modules/c++/sys/source/OSWin32.cpp @@ -60,9 +60,10 @@ std::string sys::OSWin32::getPlatformName() const { platform = "Unknown Windows OS"; } - return str::Format("%s: %d.%d [build: %d], %s", platform.c_str(), - info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber, - info.szCSDVersion); + auto retval = platform + ": "; + retval += str::Format("%d.%d [build: %d], ", info.dwMajorVersion, info.dwMinorVersion, info.dwBuildNumber); + retval += info.szCSDVersion; + return retval; } std::string sys::OSWin32::getNodeName() const @@ -113,7 +114,7 @@ void sys::OSWin32::removeFile(const std::string& pathname) const oss << "Failure removing file [" << pathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } @@ -126,7 +127,7 @@ void sys::OSWin32::removeDirectory(const std::string& pathname) const oss << "Failure removing directory [" << pathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } @@ -415,7 +416,7 @@ void sys::OSWin32::removeSymlink(const std::string& symlinkPathname) const oss << "Failure removing symlink [" << symlinkPathname << "] with error [" << err.toString() << "]"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } } diff --git a/modules/c++/sys/source/Path.cpp b/modules/c++/sys/source/Path.cpp index b775585af..510e3c4c0 100644 --- a/modules/c++/sys/source/Path.cpp +++ b/modules/c++/sys/source/Path.cpp @@ -22,6 +22,7 @@ #include "sys/Path.h" #include +#include #include namespace fs = coda_oss::filesystem; @@ -279,7 +280,7 @@ std::vector Path::list(const std::string& path) std::ostringstream oss; oss << "'" << path << "' does not exist or is not a valid directory"; - throw except::Exception(Ctxt(oss.str())); + throw except::Exception(Ctxt(oss)); } std::vector listing; Directory directory; @@ -848,5 +849,21 @@ std::string Path::expandEnvironmentVariables(const std::string& path, fs::file_t bool unused_checkIfExists = true; return expandEnvironmentVariables_(path, unused_checkIfExists, &type); } +} // sys + +template +inline auto convertPaths_(coda_oss::span paths, TFunc fun) +{ + std::vector retval; + std::transform(paths.begin(), paths.end(), std::back_inserter(retval), fun); + return retval; +} +std::vector sys::convertPaths(coda_oss::span paths) +{ + return convertPaths_(paths, [](const auto& p) { return p.string(); }); +} +std::vector sys::convertPaths(coda_oss::span paths) +{ + return convertPaths_(paths, [](const auto& p) { return p; }); } diff --git a/modules/c++/sys/source/ScopedCPUAffinityUnix.cpp b/modules/c++/sys/source/ScopedCPUAffinityUnix.cpp index e409b3b03..07f67cfe4 100644 --- a/modules/c++/sys/source/ScopedCPUAffinityUnix.cpp +++ b/modules/c++/sys/source/ScopedCPUAffinityUnix.cpp @@ -56,7 +56,7 @@ void ScopedCPUMaskUnix::initialize(int numCPUs) { std::ostringstream msg; msg << "Failed to allocate CPU mask for " << numCPUs << "CPUs"; - throw except::Exception(Ctxt(msg.str())); + throw except::Exception(Ctxt(msg)); } CPU_ZERO_S(mSize, mMask); @@ -122,7 +122,7 @@ ScopedCPUAffinityUnix::ScopedCPUAffinityUnix() : default: msg << " Unknown cause."; } - throw except::Exception(Ctxt(msg.str())); + throw except::Exception(Ctxt(msg)); } } } diff --git a/modules/c++/sys/source/sys_filesystem.cpp b/modules/c++/sys/source/sys_filesystem.cpp index 13d77f7a9..fb3126f73 100644 --- a/modules/c++/sys/source/sys_filesystem.cpp +++ b/modules/c++/sys/source/sys_filesystem.cpp @@ -48,7 +48,7 @@ fs::path::string_type fs::path::to_native(const std::string& s_) { #ifdef _WIN32 - return str::toWString(s_); + return str::details::to_wstring(s_); #else return s_; #endif @@ -103,7 +103,7 @@ fs::path::operator string_type() const std::string fs::path::string() const { - return str::toString(p_); + return str::details::to_string(p_); } fs::path fs::path::root_path() const diff --git a/modules/c++/sys/tests/OSTest.cpp b/modules/c++/sys/tests/OSTest.cpp index 330493eb7..79be99659 100644 --- a/modules/c++/sys/tests/OSTest.cpp +++ b/modules/c++/sys/tests/OSTest.cpp @@ -92,7 +92,7 @@ int main(int argc, char **argv) std::string tempFileName = os.getTempName(); std::ofstream ofs(tempFileName.c_str()); if (!ofs.is_open()) - throw except::Exception(FmtX("Could not open file named: %s", + throw except::Exception(str::Format("Could not open file named: %s", tempFileName.c_str())); ofs << "Im writing some crap to this file!" << std::endl; ofs.close(); diff --git a/modules/c++/sys/unittests/test_NaN_testing.cpp b/modules/c++/sys/unittests/test_NaN_testing.cpp index 82df40509..859e37b20 100644 --- a/modules/c++/sys/unittests/test_NaN_testing.cpp +++ b/modules/c++/sys/unittests/test_NaN_testing.cpp @@ -21,6 +21,9 @@ */ #include +#include +#include + #include "TestCase.h" TEST_CASE(testNaNsAreNotEqual) @@ -58,9 +61,40 @@ TEST_CASE(testIsNaN) TEST_ASSERT_FALSE(IS_NAN(std::string("test string"))); } +TEST_CASE(test_ssize) +{ + // https://en.cppreference.com/w/cpp/iterator/size + + // Works with containers + std::vector v{3, 1, 4}; + TEST_ASSERT_EQ(std::size(v), 3); + + // And works with built-in arrays too + int a[]{-5, 10, 15}; + // Returns the number of elements (not bytes) as opposed to sizeof + TEST_ASSERT_EQ(std::size(a), 3); + static_assert(sizeof(a) == 12, "sizeof(a)"); + + // Provides a safe way (compared to sizeof) of getting string buffer size + const char str[] = "12345"; + // These are fine and give the correct result + TEST_ASSERT_EQ(std::size(str), 6); + static_assert(sizeof(str) == 6, "sizeof(str)"); + + // But use of sizeof here is a common source of bugs + const char* str_decayed = "12345"; + static_assert(sizeof(str_decayed) == sizeof(void*), "sizeof(void*)"); + + // Since C++20 the signed size (std::ssize) is available + auto i = std::ssize(v); + for (--i; i != -1; --i) { } + TEST_ASSERT_EQ(i, -1); +} + TEST_MAIN( TEST_CHECK(testNaNsAreNotEqual); TEST_CHECK(testNaNIsNotAlmostEqualToNumber); TEST_CHECK(testIsNaN); -) + TEST_CHECK(test_ssize); + ) diff --git a/modules/c++/sys/unittests/test_os.cpp b/modules/c++/sys/unittests/test_os.cpp index 38cb01eff..802a59b88 100644 --- a/modules/c++/sys/unittests/test_os.cpp +++ b/modules/c++/sys/unittests/test_os.cpp @@ -350,7 +350,7 @@ TEST_CASE(testSpecialEnvVars) result = os.getSpecialEnv("$"); // i.e., ${$} TEST_ASSERT_FALSE(result.empty()); TEST_ASSERT_EQ(result, pid); - const auto strPid = str::toString(os.getProcessId()); + const auto strPid = std::to_string(os.getProcessId()); TEST_ASSERT_EQ(result, strPid); result = os.getSpecialEnv("PWD"); diff --git a/modules/c++/tiff/include/tiff/FileReader.h b/modules/c++/tiff/include/tiff/FileReader.h index 88edb7c41..b80d50833 100644 --- a/modules/c++/tiff/include/tiff/FileReader.h +++ b/modules/c++/tiff/include/tiff/FileReader.h @@ -20,9 +20,9 @@ * */ +#pragma once #ifndef CODA_OSS_tiff_FileReader_h_INCLUDED_ #define CODA_OSS_tiff_FileReader_h_INCLUDED_ -#pragma once #include "tiff/TiffFileReader.h" diff --git a/modules/c++/tiff/include/tiff/FileWriter.h b/modules/c++/tiff/include/tiff/FileWriter.h index d77af0d6f..e86b03453 100644 --- a/modules/c++/tiff/include/tiff/FileWriter.h +++ b/modules/c++/tiff/include/tiff/FileWriter.h @@ -20,9 +20,9 @@ * */ +#pragma once #ifndef CODA_OSS_tiff_FileWriter_h_INCLUDED_ #define CODA_OSS_tiff_FileWriter_h_INCLUDED_ -#pragma once #include "tiff/TiffFileWriter.h" diff --git a/modules/c++/tiff/include/tiff/Header.h b/modules/c++/tiff/include/tiff/Header.h index ed9da4f1e..60b9e8b67 100644 --- a/modules/c++/tiff/include/tiff/Header.h +++ b/modules/c++/tiff/include/tiff/Header.h @@ -19,11 +19,13 @@ * see . * */ - +#pragma once #ifndef __TIFF_HEADER_H__ #define __TIFF_HEADER_H__ #include +#include + #include "tiff/Common.h" namespace tiff @@ -34,7 +36,7 @@ namespace tiff * @class Header * @brief Contains TIFF header information *********************************************************************/ -class Header : public io::Serializable +class CODA_OSS_API Header : public io::Serializable { public: enum ByteOrder { MM, II }; diff --git a/modules/c++/tiff/include/tiff/IFD.h b/modules/c++/tiff/include/tiff/IFD.h index 706309e8f..ea5493db3 100644 --- a/modules/c++/tiff/include/tiff/IFD.h +++ b/modules/c++/tiff/include/tiff/IFD.h @@ -19,14 +19,16 @@ * see . * */ - +#pragma once #ifndef __TIFF_IFD_H__ #define __TIFF_IFD_H__ #include #include + #include #include +#include #include "tiff/IFDEntry.h" #include "tiff/KnownTags.h" @@ -45,7 +47,7 @@ namespace tiff * Contains functions for adding new entries to the IFD or adding * values to a specific IFD entry. *********************************************************************/ -class IFD : public io::Serializable +class CODA_OSS_API IFD : public io::Serializable { public: //! The IFDType @@ -155,8 +157,7 @@ class IFD : public io::Serializable const tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; //we can't add it if we don't know about it if (!mapEntry) - throw except::Exception(Ctxt(FmtX( - "Unable to add IFD Entry: unknown tag [%s]", name.c_str()))); + throw except::Exception(Ctxt(str::Format("Unable to add IFD Entry: unknown tag [%s]", name))); const auto id = mapEntry->getTagID(); const auto type = mapEntry->getType(); diff --git a/modules/c++/tiff/include/tiff/IFDEntry.h b/modules/c++/tiff/include/tiff/IFDEntry.h index 75552676f..e10285b99 100644 --- a/modules/c++/tiff/include/tiff/IFDEntry.h +++ b/modules/c++/tiff/include/tiff/IFDEntry.h @@ -20,17 +20,19 @@ * */ - +#pragma once #ifndef __TIFF_IFD_ENTRY_H__ #define __TIFF_IFD_ENTRY_H__ -#pragma once #include #include #include + #include -#include "tiff/GenericType.h" #include "sys/Conf.h" +#include "config/Exports.h" + +#include "tiff/GenericType.h" namespace tiff { @@ -47,7 +49,7 @@ namespace tiff * functions for printing out the entry, reading and writing it to a * file, and accessing the data. *********************************************************************/ -class IFDEntry : public io::Serializable +class CODA_OSS_API IFDEntry : public io::Serializable { public: //! Constructor diff --git a/modules/c++/tiff/include/tiff/ImageReader.h b/modules/c++/tiff/include/tiff/ImageReader.h index 65898ce70..5ca4354bf 100644 --- a/modules/c++/tiff/include/tiff/ImageReader.h +++ b/modules/c++/tiff/include/tiff/ImageReader.h @@ -19,11 +19,12 @@ * see . * */ - +#pragma once #ifndef __TIFF_IMAGE_READER_H__ #define __TIFF_IMAGE_READER_H__ #include +#include #include "tiff/IFDEntry.h" #include "tiff/IFD.h" @@ -39,7 +40,7 @@ namespace tiff * Reads a TIFF image and parses out the IFD. Contains functions for * getting data from the image and retrieving the TIFF IFD. *********************************************************************/ -class ImageReader +class CODA_OSS_API ImageReader { public: /** diff --git a/modules/c++/tiff/include/tiff/ImageWriter.h b/modules/c++/tiff/include/tiff/ImageWriter.h index 412e291f9..cd4d7a3a2 100644 --- a/modules/c++/tiff/include/tiff/ImageWriter.h +++ b/modules/c++/tiff/include/tiff/ImageWriter.h @@ -19,11 +19,12 @@ * see . * */ - +#pragma once #ifndef __TIFF_IMAGE_WRITER_H__ #define __TIFF_IMAGE_WRITER_H__ #include +#include #include "tiff/Common.h" #include "tiff/IFDEntry.h" @@ -40,7 +41,7 @@ namespace tiff * Writes a TIFF image to a stream. Contains functions for writing * the image's IFD, and for putting data to a stream. *********************************************************************/ -class ImageWriter +class CODA_OSS_API ImageWriter { public: //! The ideal tile size if a tiled file. diff --git a/modules/c++/tiff/include/tiff/KnownTags.h b/modules/c++/tiff/include/tiff/KnownTags.h index 75bd10656..c34779d03 100644 --- a/modules/c++/tiff/include/tiff/KnownTags.h +++ b/modules/c++/tiff/include/tiff/KnownTags.h @@ -19,13 +19,14 @@ * see . * */ - +#pragma once #ifndef __TIFF_KNOWN_TAGS_H__ #define __TIFF_KNOWN_TAGS_H__ #include #include #include +#include #include "tiff/IFDEntry.h" @@ -35,10 +36,8 @@ namespace tiff /** * This class is a container for known TIFF tags. */ -class KnownTags +struct CODA_OSS_API KnownTags final { -public: - KnownTags(); //! Destructor @@ -71,14 +70,13 @@ class KnownTags tiff::IFDEntry *operator[](const unsigned short tagKey); //! Some common tags - static const char IMAGE_WIDTH[]; - static const char IMAGE_LENGTH[]; - static const char BITS_PER_SAMPLE[]; - static const char COMPRESSION[]; - static const char SAMPLES_PER_PIXEL[]; - static const char PHOTOMETRIC_INTERPRETATION[]; - static const char SAMPLE_FORMAT[]; - + static constexpr auto IMAGE_WIDTH = "ImageWidth"; + static constexpr auto IMAGE_LENGTH = "ImageLength"; + static constexpr auto BITS_PER_SAMPLE = "BitsPerSample"; + static constexpr auto COMPRESSION = "Compression"; + static constexpr auto SAMPLES_PER_PIXEL = "SamplesPerPixel"; + static constexpr auto PHOTOMETRIC_INTERPRETATION = "PhotometricInterpretation"; + static constexpr auto SAMPLE_FORMAT = "SampleFormat"; /** ***************************************************************** diff --git a/modules/c++/tiff/include/tiff/TiffFileReader.h b/modules/c++/tiff/include/tiff/TiffFileReader.h index 47417b0db..9d02446e9 100644 --- a/modules/c++/tiff/include/tiff/TiffFileReader.h +++ b/modules/c++/tiff/include/tiff/TiffFileReader.h @@ -19,13 +19,15 @@ * see . * */ - +#pragma once #ifndef __TIFF_FILE_READER_H__ #define __TIFF_FILE_READER_H__ #include #include + #include +#include #include "tiff/Header.h" #include "tiff/ImageReader.h" @@ -42,7 +44,7 @@ namespace tiff * to access a specific image within the file, and to read data from * a specific image in the file. *********************************************************************/ -struct FileReader +struct CODA_OSS_API FileReader { FileReader() = default; diff --git a/modules/c++/tiff/include/tiff/TiffFileWriter.h b/modules/c++/tiff/include/tiff/TiffFileWriter.h index fb495a676..bf994ba86 100644 --- a/modules/c++/tiff/include/tiff/TiffFileWriter.h +++ b/modules/c++/tiff/include/tiff/TiffFileWriter.h @@ -19,13 +19,16 @@ * see . * */ - +#pragma once #ifndef __TIFF_FILE_WRITER_H__ #define __TIFF_FILE_WRITER_H__ #include #include + #include +#include + #include "tiff/Header.h" #include "tiff/ImageWriter.h" @@ -41,7 +44,7 @@ namespace tiff * to the same file. Contains function for manipulating each * sub-image and for writing data. *********************************************************************/ -struct FileWriter +struct CODA_OSS_API FileWriter { //! Constructor FileWriter() : @@ -191,7 +194,7 @@ template void writeTIFF(const T* image, size_t rows, size_t cols, et = ::tiff::Const::SampleFormatType::UNSIGNED_INT; break; default: - throw except::Exception(Ctxt(FmtX("Unexpected es: %d", es))); + throw except::Exception(Ctxt(str::Format("Unexpected es: %d", es))); } } unsigned short alpha(0); diff --git a/modules/c++/tiff/include/tiff/TypeFactory.h b/modules/c++/tiff/include/tiff/TypeFactory.h index 5c4f21f02..5fe9c4730 100644 --- a/modules/c++/tiff/include/tiff/TypeFactory.h +++ b/modules/c++/tiff/include/tiff/TypeFactory.h @@ -19,10 +19,12 @@ * see . * */ - +#pragma once #ifndef __TIFF_TYPE_FACTORY_H__ #define __TIFF_TYPE_FACTORY_H__ +#include "config/Exports.h" + #include "tiff/GenericType.h" namespace tiff @@ -38,7 +40,7 @@ namespace tiff * assume a specific size for the data, see tiff::Const for the size * of each TIFF type. *********************************************************************/ -class TypeFactory +class CODA_OSS_API TypeFactory final { public: //! Default constructor diff --git a/modules/c++/tiff/source/IFD.cpp b/modules/c++/tiff/source/IFD.cpp index fb145461d..09a5396a2 100644 --- a/modules/c++/tiff/source/IFD.cpp +++ b/modules/c++/tiff/source/IFD.cpp @@ -90,8 +90,7 @@ void tiff::IFD::addEntry(const std::string& name) tiff::IFDEntry *mapEntry = tiff::KnownTagsRegistry::getInstance()[name]; // we can't add it b/c we don't know about this tag if (!mapEntry) - throw except::Exception(Ctxt(FmtX( - "Unable to add IFD Entry: unknown tag [%s]", name.c_str()))); + throw except::Exception(Ctxt(str::Format("Unable to add IFD Entry: unknown tag [%s]", name))); unsigned short id = mapEntry->getTagID(); diff --git a/modules/c++/tiff/source/ImageReader.cpp b/modules/c++/tiff/source/ImageReader.cpp index 5fd42c6ad..9e5c1cbf7 100644 --- a/modules/c++/tiff/source/ImageReader.cpp +++ b/modules/c++/tiff/source/ImageReader.cpp @@ -65,7 +65,7 @@ void tiff::ImageReader::getData(unsigned char *buffer, { unsigned short c = *(tiff::GenericType *)(*compression)[0]; if (c != tiff::Const::CompressionType::NO_COMPRESSION) - throw except::Exception(Ctxt(FmtX("Unsupported compression type: %d", c))); + throw except::Exception(Ctxt(str::Format("Unsupported compression type: %d", c))); } if (mIFD["StripOffsets"]) diff --git a/modules/c++/tiff/source/KnownTags.cpp b/modules/c++/tiff/source/KnownTags.cpp index 60b329079..ad7fa8982 100644 --- a/modules/c++/tiff/source/KnownTags.cpp +++ b/modules/c++/tiff/source/KnownTags.cpp @@ -28,14 +28,6 @@ #include "tiff/IFDEntry.h" #include -const char tiff::KnownTags::IMAGE_WIDTH[] = "ImageWidth"; -const char tiff::KnownTags::IMAGE_LENGTH[] = "ImageLength"; -const char tiff::KnownTags::BITS_PER_SAMPLE[] = "BitsPerSample"; -const char tiff::KnownTags::COMPRESSION[] = "Compression"; -const char tiff::KnownTags::SAMPLES_PER_PIXEL[] = "SamplesPerPixel"; -const char tiff::KnownTags::PHOTOMETRIC_INTERPRETATION[] = "PhotometricInterpretation"; -const char tiff::KnownTags::SAMPLE_FORMAT[] = "SampleFormat"; - tiff::KnownTags::KnownTags() { addEntry(254, tiff::Const::Type::LONG, "NewSubfileType"); diff --git a/modules/c++/tiff/source/TiffFileReader.cpp b/modules/c++/tiff/source/TiffFileReader.cpp index e0d78f841..812a1bb9c 100644 --- a/modules/c++/tiff/source/TiffFileReader.cpp +++ b/modules/c++/tiff/source/TiffFileReader.cpp @@ -79,7 +79,7 @@ void tiff::FileReader::close() tiff::ImageReader *tiff::FileReader::operator[](const sys::Uint32_T index) const { if (index >= mImages.size()) - throw except::Exception(Ctxt(FmtX("Index out of range: %d", index))); + throw except::Exception(Ctxt(str::Format("Index out of range: %d", index))); return mImages[index]; } @@ -106,7 +106,7 @@ void tiff::FileReader::getData(unsigned char *buffer, const sys::Uint32_T numElementsToRead, const sys::Uint32_T imageIndex) { if (imageIndex >= mImages.size()) - throw except::Exception(Ctxt(FmtX("Index out of range", imageIndex))); + throw except::Exception(Ctxt(str::Format("Index out of range", imageIndex))); mImages[imageIndex]->getData(buffer, numElementsToRead); } diff --git a/modules/c++/tiff/source/Utils.cpp b/modules/c++/tiff/source/Utils.cpp index ff6e60d04..0c15220d5 100644 --- a/modules/c++/tiff/source/Utils.cpp +++ b/modules/c++/tiff/source/Utils.cpp @@ -106,9 +106,8 @@ tiff::IFD* tiff::Utils::createGeoTiffIFD(tiff::IFD* ifd) if (idx + 3 >= geoVals.size()) { throw except::Exception(Ctxt( - "'GeoKeyDirectoryTag' specified " + - str::toString(numKeys) + " keys but the IFD entry only had " + - str::toString(geoVals.size()) + " values")); + "'GeoKeyDirectoryTag' specified " + + std::to_string(numKeys) + " keys but the IFD entry only had " + std::to_string(geoVals.size()) + " values")); } const unsigned short keyId = @@ -143,8 +142,7 @@ tiff::IFD* tiff::Utils::createGeoTiffIFD(tiff::IFD* ifd) { if (count != 1) { - throw except::Exception(Ctxt( - "Expected a count of 1 but got " + str::toString(count))); + throw except::Exception(Ctxt("Expected a count of 1 but got " + std::to_string(count))); } entry->addValue(new tiff::GenericType(valueStr)); diff --git a/modules/c++/tiff/tests/DumpHeader.cpp b/modules/c++/tiff/tests/DumpHeader.cpp index 1c310f441..2e0be41cb 100644 --- a/modules/c++/tiff/tests/DumpHeader.cpp +++ b/modules/c++/tiff/tests/DumpHeader.cpp @@ -31,7 +31,7 @@ int main(int argc, char **argv) try { if (argc < 2) - throw except::Exception(FmtX("usage: %s ", argv[0])); + throw except::Exception(str::Format("usage: %s ", argv[0])); sys::OS os; std::string path = sys::Path::absolutePath(argv[1]); @@ -47,7 +47,7 @@ int main(int argc, char **argv) if (tiff::Utils::hasGeoTiffIFD(reader[i]->getIFD())) { outStream.writeln("==========================="); - outStream.writeln(FmtX("GeoTIFF detected: Image %d\n", (i + 1))); + outStream.writeln(str::Format("GeoTIFF detected: Image %d\n", (i + 1))); tiff::IFD *geoIFD = tiff::Utils::createGeoTiffIFD(reader[i]->getIFD()); geoIFD->print(outStream); diff --git a/modules/c++/types/include/types/RowCol.h b/modules/c++/types/include/types/RowCol.h index e13f125a2..846280aaa 100644 --- a/modules/c++/types/include/types/RowCol.h +++ b/modules/c++/types/include/types/RowCol.h @@ -19,7 +19,7 @@ * see . * */ - + #pragma once #ifndef __TYPES_ROW_COL_H__ #define __TYPES_ROW_COL_H__ @@ -28,6 +28,7 @@ #include #include #include +#include #include "gsl/gsl.h" @@ -78,6 +79,11 @@ template class RowCol row = p.first; col = p.second; } + explicit RowCol(const std::array& a) noexcept + { + row = a[0]; + col = a[1]; + } template RowCol& operator=(const RowCol& p) noexcept { diff --git a/modules/c++/xml.lite/include/xml/lite/Element.h b/modules/c++/xml.lite/include/xml/lite/Element.h index 01c5aab0c..ee4e05346 100644 --- a/modules/c++/xml.lite/include/xml/lite/Element.h +++ b/modules/c++/xml.lite/include/xml/lite/Element.h @@ -319,7 +319,7 @@ struct CODA_OSS_API Element // SOAPElement derives :-( * \return the charater data */ std::string getCharacterData() const; - coda_oss::u8string& getCharacterData(coda_oss::u8string& result) const; + const coda_oss::u8string& getCharacterData(coda_oss::u8string& result) const; //explicit operator coda_oss::u8string() const //{ // coda_oss::u8string result; @@ -499,7 +499,7 @@ struct CODA_OSS_API Element // SOAPElement derives :-( coda_oss::u8string mCharacterData; }; -Element& add(const xml::lite::QName&, const std::string& value, Element& parent); +CODA_OSS_API Element& add(const xml::lite::QName&, const std::string& value, Element& parent); #ifndef SWIG // The (old) version of SWIG we're using doesn't like certain C++11 features. diff --git a/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h b/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h index ef2039123..159bbb6ea 100644 --- a/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h +++ b/modules/c++/xml.lite/include/xml/lite/UtilitiesXerces.h @@ -29,6 +29,7 @@ #include #include #include +#include #include "config/compiler_extensions.h" #include "config/Exports.h" @@ -409,17 +410,20 @@ struct XercesErrorHandler final : public XercesErrorHandlerInterface_T */ struct CODA_OSS_API XercesContext final { - //! Constructor XercesContext(); - - //! Destructor ~XercesContext(); + XercesContext(const XercesContext&) = delete; + XercesContext& operator=(const XercesContext&) = delete; + XercesContext(XercesContext&&) = delete; + XercesContext& operator=(XercesContext&&) = delete; + void destroy(); private: - static std::mutex mMutex; - bool mIsDestroyed; + struct Impl; + static std::shared_ptr getInstance(); + std::shared_ptr mpImpl; }; } } diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h b/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h index 4e50656ef..024c0a8b1 100644 --- a/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorInterface.h @@ -79,7 +79,7 @@ struct ValidationInfo final std::ostringstream oss; oss << "[" << this->getLevel() << "]" << " from File: " << this->getFile() << - " on Line: " << str::toString(this->getLine()) << + " on Line: " << this->getLine() << " with Message: " << this->getMessage(); return oss.str(); } diff --git a/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h b/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h index 8d5d79ba0..56e9689ae 100644 --- a/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h +++ b/modules/c++/xml.lite/include/xml/lite/ValidatorXerces.h @@ -89,12 +89,8 @@ struct ValidationErrorHandler final : public xercesc::DOMErrorHandler * * This class is the Xercesc schema validator */ -class CODA_OSS_API ValidatorXerces : public ValidatorInterface +struct CODA_OSS_API ValidatorXerces : public ValidatorInterface { - XercesContext mCtxt; //! this must be the first member listed - -public: - /*! * Constructor * \param schemaPaths Vector of both paths and singular schemas @@ -104,10 +100,10 @@ class CODA_OSS_API ValidatorXerces : public ValidatorInterface * input */ ValidatorXerces(const std::vector& schemaPaths, - logging::Logger* log, + logging::Logger* log = nullptr, bool recursive = true); - ValidatorXerces(const std::vector&, // fs::path -> mLegacyStringConversion = false - logging::Logger* log, + ValidatorXerces(const std::vector&, + logging::Logger* log = nullptr, bool recursive = true); ValidatorXerces(const ValidatorXerces&) = delete; @@ -133,6 +129,8 @@ class CODA_OSS_API ValidatorXerces : public ValidatorInterface static std::vector loadSchemas(const std::vector& schemaPaths, bool recursive=true); private: + XercesContext mCtxt; + bool validate_(const coda_oss::u8string& xml, const std::string& xmlID, std::vector& errors) const; diff --git a/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h b/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h index a808be8d8..d40aea202 100644 --- a/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h +++ b/modules/c++/xml.lite/include/xml/lite/XMLReaderXerces.h @@ -61,7 +61,7 @@ namespace lite */ class CODA_OSS_API XMLReaderXerces final : public XMLReaderInterface { - XercesContext mCtxt; //! this must be the first member listed + XercesContext mCtxt; std::unique_ptr mNative; std::unique_ptr mDriverContentHandler; std::unique_ptr mErrorHandler; diff --git a/modules/c++/xml.lite/source/Attributes.cpp b/modules/c++/xml.lite/source/Attributes.cpp index 2628ca7c8..aff257256 100644 --- a/modules/c++/xml.lite/source/Attributes.cpp +++ b/modules/c++/xml.lite/source/Attributes.cpp @@ -81,7 +81,7 @@ std::string xml::lite::Attributes::getValue(int i) const } catch (const std::out_of_range& ex) { - throw except::NoSuchKeyException(Ctxt(FmtX("attributes[%d] not found, %s", i, ex.what()))); + throw except::NoSuchKeyException(Ctxt(str::Format("attributes[%d] not found, %s", i, ex.what()))); } } bool xml::lite::Attributes::getValue(int i, std::string& result) const @@ -125,8 +125,7 @@ std::string xml::lite::Attributes::getValue(const std::string& qname) const std::string retval; if (!getValue(qname, retval)) { - throw except::NoSuchKeyException(Ctxt(FmtX("QName '%s' could not be found", - qname.c_str()))); + throw except::NoSuchKeyException(Ctxt(str::Format("QName '%s' could not be found", qname))); } return retval; @@ -152,7 +151,7 @@ std::string xml::lite::Attributes::getValue(const QName& qname) const { const auto uri = qname.getUri().value; const auto localName = qname.getName(); - throw except::NoSuchKeyException(Ctxt(FmtX("(uri: %s, localName: %s", uri, localName))); + throw except::NoSuchKeyException(Ctxt(str::Format("(uri: %s, localName: %s", uri, localName))); } return retval; } diff --git a/modules/c++/xml.lite/source/Element.cpp b/modules/c++/xml.lite/source/Element.cpp index 80470ab02..dcc211e6c 100644 --- a/modules/c++/xml.lite/source/Element.cpp +++ b/modules/c++/xml.lite/source/Element.cpp @@ -129,7 +129,7 @@ std::tuple getElement(TGetElements getElements { return std::make_tuple(elements[0], ""); } - return std::make_tuple(nullptr, str::toString(elements.size())); + return std::make_tuple(nullptr, std::to_string(elements.size())); } template xml::lite::Element& getElement(TGetElements getElements, TMakeContext makeContext) @@ -259,9 +259,9 @@ void xml::lite::Element::prettyConsoleOutput_(io::OutputStream& stream, std::string xml::lite::Element::getCharacterData() const { - return str::toString(mCharacterData); + return str::to_native(mCharacterData); } -coda_oss::u8string& xml::lite::Element::getCharacterData(coda_oss::u8string& result) const +const coda_oss::u8string& xml::lite::Element::getCharacterData(coda_oss::u8string& result) const { result = mCharacterData; return result; @@ -278,7 +278,7 @@ static void writeCharacterData_utf8(io::OutputStream& stream, const std::u8strin } static void writeCharacterData_native(io::OutputStream& stream, const std::u8string& characterData) { - stream.write(str::toString(characterData)); + stream.write(str::to_native(characterData)); } static void depthPrint_(const xml::lite::Element& element, @@ -465,7 +465,7 @@ void xml::lite::Element::setNamespaceURI( void xml::lite::Element::setCharacterData(const std::string& characters) { - mCharacterData = str::u8FromString(characters); + mCharacterData = str::u8FromNative(characters); } xml::lite::Element& xml::lite::Element::operator=(const std::string& characterData) { @@ -506,7 +506,7 @@ xml::lite::Element& xml::lite::addChild(Element& e, const QName& qname, const co } xml::lite::Element& xml::lite::addChild(Element& e, const QName& qname, const std::string& characterData) { - return addChild(e, qname, str::u8FromString(characterData)); + return addChild(e, qname, str::u8FromNative(characterData)); } xml::lite::Element& xml::lite::addChild(Element& e, const QName& qname) { diff --git a/modules/c++/xml.lite/source/MinidomHandler.cpp b/modules/c++/xml.lite/source/MinidomHandler.cpp index f895562c4..009ab29e5 100644 --- a/modules/c++/xml.lite/source/MinidomHandler.cpp +++ b/modules/c++/xml.lite/source/MinidomHandler.cpp @@ -73,7 +73,7 @@ void xml::lite::MinidomHandler::characters(const char *value, int length) // If we're still here despite use_char() being "false" then the // wide-character routine "failed." On Windows, that means the char* value // is encoded as Windows-1252 (more-or-less ISO8859-1). - characters(str::u8FromString(std::string(value, length))); + characters(str::u8FromNative(std::string(value, length))); } bool xml::lite::MinidomHandler::vcharacters(const void /*XMLCh*/* chars_, size_t length) diff --git a/modules/c++/xml.lite/source/UtilitiesXerces.cpp b/modules/c++/xml.lite/source/UtilitiesXerces.cpp index ffb0f7fd7..943eb5e5f 100644 --- a/modules/c++/xml.lite/source/UtilitiesXerces.cpp +++ b/modules/c++/xml.lite/source/UtilitiesXerces.cpp @@ -28,8 +28,6 @@ namespace xml { namespace lite { -std::mutex XercesContext::mMutex; - XercesLocalString::XercesLocalString(XMLCh* xmlStr) : mLocal(xmlStr) { @@ -186,8 +184,16 @@ fatalError(const SAXParseException &exception) throw except::Error(Ctxt(xex.getMessage())); } -XercesContext::XercesContext() : - mIsDestroyed(false) +/*! + * \class XercesContext::Impl + * \brief This class safely creates and destroys Xerces + */ +struct XercesContext::Impl final +{ + static std::mutex mMutex; + bool mIsDestroyed = false; + +Impl() { //! XMLPlatformUtils::Initialize is not thread safe! try @@ -203,7 +209,7 @@ XercesContext::XercesContext() : } } -XercesContext::~XercesContext() +~Impl() { try { @@ -214,7 +220,7 @@ XercesContext::~XercesContext() } } -void XercesContext::destroy() +void destroy() { // wrapping it here saves the mutex lock if (!mIsDestroyed) @@ -235,7 +241,28 @@ void XercesContext::destroy() } } } +}; +std::mutex XercesContext::Impl::mMutex; + +std::shared_ptr XercesContext::getInstance() +{ + // The one and only instance; call XMLPlatformUtils::Initialize() and XMLPlatformUtils::Terminate() just once. + static auto impl = std::make_shared(); + return impl; // increment reference count +} +XercesContext::XercesContext() : mpImpl(getInstance()) // increment reference count +{ +} +XercesContext::~XercesContext() +{ + destroy(); } +void XercesContext::destroy() +{ + mpImpl.reset(); } +} // lite +} // xml + #endif diff --git a/modules/c++/xml.lite/source/ValidatorXerces.cpp b/modules/c++/xml.lite/source/ValidatorXerces.cpp index 46d5c7bc8..dba996bd9 100644 --- a/modules/c++/xml.lite/source/ValidatorXerces.cpp +++ b/modules/c++/xml.lite/source/ValidatorXerces.cpp @@ -37,6 +37,7 @@ CODA_OSS_disable_warning(-Wshadow) CODA_OSS_disable_warning_pop #include +#include #include #include @@ -89,26 +90,11 @@ bool ValidationErrorHandler::handleError( return true; } -inline std::vector convert(const std::vector& schemaPaths) -{ - std::vector retval; - std::transform(schemaPaths.begin(), schemaPaths.end(), std::back_inserter(retval), - [](const fs::path& p) { return p.string(); }); - return retval; -} -inline auto convert(const std::vector& paths) -{ - std::vector retval; - std::transform(paths.begin(), paths.end(), std::back_inserter(retval), - [](const auto& p) { return p; }); - return retval; -} - ValidatorXerces::ValidatorXerces( const std::vector& schemaPaths, logging::Logger* log, bool recursive) : - ValidatorXerces(convert(schemaPaths), log, recursive) + ValidatorXerces(sys::convertPaths(schemaPaths), log, recursive) { } ValidatorXerces::ValidatorXerces( @@ -169,7 +155,7 @@ ValidatorXerces::ValidatorXerces( // load our schemas -- // search each directory for schemas - const auto schemas = loadSchemas(convert(schemaPaths), recursive); + const auto schemas = loadSchemas(sys::convertPaths(schemaPaths), recursive); // add the schema to the validator // add the schema to the validator @@ -179,9 +165,12 @@ ValidatorXerces::ValidatorXerces( xercesc::Grammar::SchemaGrammarType, true)) { - std::ostringstream oss; - oss << "Error: Failure to load schema " << schema; - log->warn(Ctxt(oss.str())); + if (log != nullptr) + { + std::ostringstream oss; + oss << "Error: Failure to load schema " << schema; + log->warn(Ctxt(oss)); + } } } @@ -207,7 +196,7 @@ using XMLCh_t = wchar_t; static_assert(std::is_same<::XMLCh, XMLCh_t>::value, "XMLCh should be wchar_t"); inline void reset(const std::u8string& xml, std::unique_ptr& pWString) { - pWString = std::make_unique(str::toWString(xml)); + pWString = std::make_unique(str::details::to_wstring(xml)); } #else using XMLCh_t = char16_t; @@ -283,8 +272,8 @@ static coda_oss::u8string encodeXml(const std::string& xml) return to_u8string(str::str(xml)); } - // No "... encoding= ..."; let u8FromString() deal with it - return str::u8FromString(xml); + // No "... encoding= ..."; let u8FromNative() deal with it + return str::u8FromNative(xml); } bool ValidatorXerces::validate(const std::string& xml, diff --git a/modules/c++/xml.lite/tests/AttributeValueTest.cpp b/modules/c++/xml.lite/tests/AttributeValueTest.cpp index c66f466ca..01e66e1e0 100644 --- a/modules/c++/xml.lite/tests/AttributeValueTest.cpp +++ b/modules/c++/xml.lite/tests/AttributeValueTest.cpp @@ -41,7 +41,7 @@ int main(int argc, char **argv) // Check to make sure we have right length if (argc != 2) - throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + throw Exception(Ctxt(str::Format("Usage: %s \n", argv[0]))); // Create an input stream FileInputStream xmlFile(argv[1]); diff --git a/modules/c++/xml.lite/tests/MinidomParserTest1.cpp b/modules/c++/xml.lite/tests/MinidomParserTest1.cpp index ac5ffa42e..aaa37b9ab 100644 --- a/modules/c++/xml.lite/tests/MinidomParserTest1.cpp +++ b/modules/c++/xml.lite/tests/MinidomParserTest1.cpp @@ -39,7 +39,7 @@ int main(int argc, char **argv) // Check to make sure we have right length if (argc != 2) - throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + throw Exception(Ctxt(str::Format("Usage: %s \n", argv[0]))); // Create an input stream FileInputStream xmlFile(argv[1]); diff --git a/modules/c++/xml.lite/tests/MinidomParserTest2.cpp b/modules/c++/xml.lite/tests/MinidomParserTest2.cpp index ee28d77d8..78c01da3b 100644 --- a/modules/c++/xml.lite/tests/MinidomParserTest2.cpp +++ b/modules/c++/xml.lite/tests/MinidomParserTest2.cpp @@ -52,7 +52,7 @@ int main(int argc, char **argv) { if (argc != 5) { - throw Exception(Ctxt(FmtX( + throw Exception(Ctxt(str::Format( "Usage: %s [OPTION] \n\n\t-a\tadd service\n\t-s\tsubtract service\n\t-o\toutput file\n", argv[0]))); } @@ -123,7 +123,7 @@ int main(int argc, char **argv) if (rootElement) rootElement->print(out); break; default: - throw Exception(Ctxt(FmtX( + throw Exception(Ctxt(str::Format( "Usage: %s [OPTION] \n\n\t-a\tadd service\n\t-s\tsubtract service\n\t-o\toutput file\n", argv[0]))); } diff --git a/modules/c++/xml.lite/tests/XMLReaderTest.cpp b/modules/c++/xml.lite/tests/XMLReaderTest.cpp index 8e4cf9a08..83989cb4a 100644 --- a/modules/c++/xml.lite/tests/XMLReaderTest.cpp +++ b/modules/c++/xml.lite/tests/XMLReaderTest.cpp @@ -134,7 +134,7 @@ int main(int argc, char **argv) { // Check to make sure we have right length if (argc != 2) - throw Exception(Ctxt(FmtX("Usage: %s \n", argv[0]))); + throw Exception(Ctxt(str::Format("Usage: %s \n", argv[0]))); // Create an input stream FileInputStream diff --git a/modules/c++/xml.lite/unittests/test_xmlcreate.cpp b/modules/c++/xml.lite/unittests/test_xmlcreate.cpp index 7d982ef18..08cffd845 100644 --- a/modules/c++/xml.lite/unittests/test_xmlcreate.cpp +++ b/modules/c++/xml.lite/unittests/test_xmlcreate.cpp @@ -115,11 +115,11 @@ TEST_CASE(testXmlCreateWhitespace) xml::lite::MinidomParser xmlParser; auto& document = getDocument(xmlParser); - const auto text = str::u8FromString(" "); + const auto text = str::u8FromNative(" "); auto documents_ = document.createElement(xml::lite::QName(""_u, "text"), text); auto& documents = *documents_; - auto strXml = str::u8FromString(print(documents)); - const auto expected = str::u8FromString("") + text + str::u8FromString(""); + auto strXml = str::u8FromNative(print(documents)); + const auto expected = str::u8FromNative("") + text + str::u8FromNative(""); TEST_ASSERT(strXml == expected); { diff --git a/modules/c++/xml.lite/unittests/test_xmlelement.cpp b/modules/c++/xml.lite/unittests/test_xmlelement.cpp index 0c252e12a..2f42d5b38 100644 --- a/modules/c++/xml.lite/unittests/test_xmlelement.cpp +++ b/modules/c++/xml.lite/unittests/test_xmlelement.cpp @@ -21,6 +21,7 @@ */ #include +#include #include "coda_oss/CPlusPlus.h" #include "io/StringStream.h" #include @@ -101,7 +102,7 @@ TEST_CASE(test_getElementsByTagName) { const auto aElements = root.getElementsByTagName("a", true /*recurse*/); - TEST_ASSERT_EQ(aElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(aElements), 1); const auto& a = *(aElements[0]); const auto characterData = a.getCharacterData(); @@ -113,7 +114,7 @@ TEST_CASE(test_getElementsByTagName) TEST_ASSERT_EQ(docElements.size(), static_cast(1)); { const auto aElements = docElements[0]->getElementsByTagName("a"); - TEST_ASSERT_EQ(aElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(aElements), 1); const auto& a = *(aElements[0]); const auto characterData = a.getCharacterData(); @@ -137,10 +138,10 @@ TEST_CASE(test_getElementsByTagName_duplicate) const auto docElements = root.getElementsByTagName("doc"); TEST_ASSERT_FALSE(docElements.empty()); - TEST_ASSERT_EQ(docElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(docElements), 1); { const auto duplicateElements = docElements[0]->getElementsByTagName("duplicate"); - TEST_ASSERT_EQ(duplicateElements.size(), static_cast(2)); + TEST_ASSERT_EQ(std::ssize(duplicateElements), 2); const auto& duplicate = *(duplicateElements[0]); const auto characterData = duplicate.getCharacterData(); diff --git a/modules/c++/xml.lite/unittests/test_xmlparser.cpp b/modules/c++/xml.lite/unittests/test_xmlparser.cpp index 32deee263..b39f411fb 100644 --- a/modules/c++/xml.lite/unittests/test_xmlparser.cpp +++ b/modules/c++/xml.lite/unittests/test_xmlparser.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "io/StringStream.h" #include "io/FileInputStream.h" @@ -59,7 +60,7 @@ static const std::u8string& text8() static const auto& iso88591Text1252() { - static const str::W1252string retval = str::cast("T\xc9XT"); // ISO8859-1, "TXT" + static const auto retval = str::make_string("T\xc9XT"); // ISO8859-1, "TXT" return retval; } static auto pIso88591Text_() @@ -70,7 +71,7 @@ static auto pIso88591Text_() static const auto& utf8Text8() { - static const coda_oss::u8string retval = str::cast("T\xc3\x89XT"); // UTF-8, "TXT" + static const auto retval = str::make_string("T\xc3\x89XT"); // UTF-8, "TXT" return retval; } static const auto pUtf8Text_() @@ -105,7 +106,7 @@ static std::filesystem::path find_unittest_file(const std::filesystem::path& nam static void test_a_element(const std::string& testName, const xml::lite::Element& root) { const auto aElements = root.getElementsByTagName("a", true /*recurse*/); - TEST_ASSERT_EQ(aElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(aElements), 1); const auto& a = *(aElements[0]); const auto characterData = a.getCharacterData(); @@ -124,7 +125,7 @@ TEST_CASE(testXmlParseSimple) const auto docElements = root.getElementsByTagName("doc"); TEST_ASSERT_FALSE(docElements.empty()); - TEST_ASSERT_EQ(docElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(docElements), 1); test_a_element(testName, *docElements[0]); } @@ -365,7 +366,7 @@ static void testReadXmlFile(const std::string& testName, const std::string& xmlF const auto& root = getRootElement(getDocument(xmlParser)); const auto aElements = root.getElementsByTagName("a", true /*recurse*/); - TEST_ASSERT_EQ(aElements.size(), static_cast(1)); + TEST_ASSERT_EQ(std::ssize(aElements), 1); const auto& a = *(aElements[0]); auto characterData = a.getCharacterData(); @@ -462,8 +463,8 @@ static void testValidateXmlFile_(const std::string& testName, const std::string& static const auto xsd = find_unittest_file("doc.xsd"); const auto path = find_unittest_file(xmlFile); - const std::vector schemaPaths{xsd.parent_path()}; // fs::path -> new string-conversion code - const xml::lite::Validator validator(schemaPaths, nullptr /*log*/); + const std::vector schemaPaths{xsd.parent_path()}; + const xml::lite::Validator validator(schemaPaths); io::FileInputStream fis(path); std::vector errors; diff --git a/modules/c++/zip/include/zip/ZipFile.h b/modules/c++/zip/include/zip/ZipFile.h index 6e7c7e6e6..b81927d74 100644 --- a/modules/c++/zip/include/zip/ZipFile.h +++ b/modules/c++/zip/include/zip/ZipFile.h @@ -23,6 +23,8 @@ #ifndef __ZIP_ZIP_FILE_H__ #define __ZIP_ZIP_FILE_H__ +#include "gsl/gsl.h" + #include "zip/ZipEntry.h" /*! @@ -144,9 +146,9 @@ class ZipFile return mComment; } - unsigned long getNumEntries() const + auto getNumEntries() const { - return static_cast(mEntries.size()); + return gsl::narrow(mEntries.size()); } }; diff --git a/modules/c++/zip/source/ZipEntry.cpp b/modules/c++/zip/source/ZipEntry.cpp index 4c9352672..14bc85be1 100644 --- a/modules/c++/zip/source/ZipEntry.cpp +++ b/modules/c++/zip/source/ZipEntry.cpp @@ -50,7 +50,7 @@ void ZipEntry::inflate(sys::ubyte* out, sys::Size_T outLen, sys::ubyte* in, int zerr = inflateInit2(&zstream, -MAX_WBITS); if (zerr != Z_OK) { - throw except::IOException(Ctxt(FmtX("inflateInit2 failed [%d]", zerr))); + throw except::IOException(Ctxt(str::Format("inflateInit2 failed [%d]", zerr))); } // decompress @@ -58,7 +58,7 @@ void ZipEntry::inflate(sys::ubyte* out, sys::Size_T outLen, sys::ubyte* in, if (zerr != Z_STREAM_END) { - throw except::IOException(Ctxt(FmtX( + throw except::IOException(Ctxt(str::Format( "inflate failed [%d]: wanted: %d, got: %lu", zerr, Z_STREAM_END, zstream.total_out))); } diff --git a/modules/drivers/hdf5/include/H5HLprivate2.h b/modules/drivers/hdf5/include/H5HLprivate2.h new file mode 100644 index 000000000..2bd8d0191 --- /dev/null +++ b/modules/drivers/hdf5/include/H5HLprivate2.h @@ -0,0 +1,25 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5HLprivate2_H +#define H5HLprivate2_H + +/* Public HDF5 header */ +#include "hdf5.h" + +/* Public High-Level header */ +#include "hdf5_hl.h" + +/* HDF5 private functions */ +#include "H5private.h" + +#endif /* H5HLprivate2_H */ diff --git a/modules/drivers/hdf5/include/H5LTparse.h b/modules/drivers/hdf5/include/H5LTparse.h new file mode 100644 index 000000000..84c5fd093 --- /dev/null +++ b/modules/drivers/hdf5/include/H5LTparse.h @@ -0,0 +1,142 @@ +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +#ifndef YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED +# define YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int H5LTyydebug; +#endif + +/* Token kinds. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + YYEMPTY = -2, + YYEOF = 0, /* "end of file" */ + YYerror = 256, /* error */ + YYUNDEF = 257, /* "invalid token" */ + H5T_STD_I8BE_TOKEN = 258, /* H5T_STD_I8BE_TOKEN */ + H5T_STD_I8LE_TOKEN = 259, /* H5T_STD_I8LE_TOKEN */ + H5T_STD_I16BE_TOKEN = 260, /* H5T_STD_I16BE_TOKEN */ + H5T_STD_I16LE_TOKEN = 261, /* H5T_STD_I16LE_TOKEN */ + H5T_STD_I32BE_TOKEN = 262, /* H5T_STD_I32BE_TOKEN */ + H5T_STD_I32LE_TOKEN = 263, /* H5T_STD_I32LE_TOKEN */ + H5T_STD_I64BE_TOKEN = 264, /* H5T_STD_I64BE_TOKEN */ + H5T_STD_I64LE_TOKEN = 265, /* H5T_STD_I64LE_TOKEN */ + H5T_STD_U8BE_TOKEN = 266, /* H5T_STD_U8BE_TOKEN */ + H5T_STD_U8LE_TOKEN = 267, /* H5T_STD_U8LE_TOKEN */ + H5T_STD_U16BE_TOKEN = 268, /* H5T_STD_U16BE_TOKEN */ + H5T_STD_U16LE_TOKEN = 269, /* H5T_STD_U16LE_TOKEN */ + H5T_STD_U32BE_TOKEN = 270, /* H5T_STD_U32BE_TOKEN */ + H5T_STD_U32LE_TOKEN = 271, /* H5T_STD_U32LE_TOKEN */ + H5T_STD_U64BE_TOKEN = 272, /* H5T_STD_U64BE_TOKEN */ + H5T_STD_U64LE_TOKEN = 273, /* H5T_STD_U64LE_TOKEN */ + H5T_NATIVE_CHAR_TOKEN = 274, /* H5T_NATIVE_CHAR_TOKEN */ + H5T_NATIVE_SCHAR_TOKEN = 275, /* H5T_NATIVE_SCHAR_TOKEN */ + H5T_NATIVE_UCHAR_TOKEN = 276, /* H5T_NATIVE_UCHAR_TOKEN */ + H5T_NATIVE_SHORT_TOKEN = 277, /* H5T_NATIVE_SHORT_TOKEN */ + H5T_NATIVE_USHORT_TOKEN = 278, /* H5T_NATIVE_USHORT_TOKEN */ + H5T_NATIVE_INT_TOKEN = 279, /* H5T_NATIVE_INT_TOKEN */ + H5T_NATIVE_UINT_TOKEN = 280, /* H5T_NATIVE_UINT_TOKEN */ + H5T_NATIVE_LONG_TOKEN = 281, /* H5T_NATIVE_LONG_TOKEN */ + H5T_NATIVE_ULONG_TOKEN = 282, /* H5T_NATIVE_ULONG_TOKEN */ + H5T_NATIVE_LLONG_TOKEN = 283, /* H5T_NATIVE_LLONG_TOKEN */ + H5T_NATIVE_ULLONG_TOKEN = 284, /* H5T_NATIVE_ULLONG_TOKEN */ + H5T_IEEE_F32BE_TOKEN = 285, /* H5T_IEEE_F32BE_TOKEN */ + H5T_IEEE_F32LE_TOKEN = 286, /* H5T_IEEE_F32LE_TOKEN */ + H5T_IEEE_F64BE_TOKEN = 287, /* H5T_IEEE_F64BE_TOKEN */ + H5T_IEEE_F64LE_TOKEN = 288, /* H5T_IEEE_F64LE_TOKEN */ + H5T_NATIVE_FLOAT_TOKEN = 289, /* H5T_NATIVE_FLOAT_TOKEN */ + H5T_NATIVE_DOUBLE_TOKEN = 290, /* H5T_NATIVE_DOUBLE_TOKEN */ + H5T_NATIVE_LDOUBLE_TOKEN = 291, /* H5T_NATIVE_LDOUBLE_TOKEN */ + H5T_STRING_TOKEN = 292, /* H5T_STRING_TOKEN */ + STRSIZE_TOKEN = 293, /* STRSIZE_TOKEN */ + STRPAD_TOKEN = 294, /* STRPAD_TOKEN */ + CSET_TOKEN = 295, /* CSET_TOKEN */ + CTYPE_TOKEN = 296, /* CTYPE_TOKEN */ + H5T_VARIABLE_TOKEN = 297, /* H5T_VARIABLE_TOKEN */ + H5T_STR_NULLTERM_TOKEN = 298, /* H5T_STR_NULLTERM_TOKEN */ + H5T_STR_NULLPAD_TOKEN = 299, /* H5T_STR_NULLPAD_TOKEN */ + H5T_STR_SPACEPAD_TOKEN = 300, /* H5T_STR_SPACEPAD_TOKEN */ + H5T_CSET_ASCII_TOKEN = 301, /* H5T_CSET_ASCII_TOKEN */ + H5T_CSET_UTF8_TOKEN = 302, /* H5T_CSET_UTF8_TOKEN */ + H5T_C_S1_TOKEN = 303, /* H5T_C_S1_TOKEN */ + H5T_FORTRAN_S1_TOKEN = 304, /* H5T_FORTRAN_S1_TOKEN */ + H5T_OPAQUE_TOKEN = 305, /* H5T_OPAQUE_TOKEN */ + OPQ_SIZE_TOKEN = 306, /* OPQ_SIZE_TOKEN */ + OPQ_TAG_TOKEN = 307, /* OPQ_TAG_TOKEN */ + H5T_COMPOUND_TOKEN = 308, /* H5T_COMPOUND_TOKEN */ + H5T_ENUM_TOKEN = 309, /* H5T_ENUM_TOKEN */ + H5T_ARRAY_TOKEN = 310, /* H5T_ARRAY_TOKEN */ + H5T_VLEN_TOKEN = 311, /* H5T_VLEN_TOKEN */ + STRING = 312, /* STRING */ + NUMBER = 313 /* NUMBER */ + }; + typedef enum yytokentype yytoken_kind_t; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +union YYSTYPE +{ +#line 68 "hl/src//H5LTparse.y" + + int ival; /*for integer token*/ + char *sval; /*for name string*/ + hid_t hid; /*for hid_t token*/ + +#line 128 "hl/src//H5LTparse.h" + +}; +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + + +extern YYSTYPE H5LTyylval; + + +hid_t H5LTyyparse (void); + + +#endif /* !YY_H5LTYY_HL_SRC_H5LTPARSE_H_INCLUDED */ diff --git a/modules/drivers/hdf5/include/H5LTprivate.h b/modules/drivers/hdf5/include/H5LTprivate.h new file mode 100644 index 000000000..bea2e63c8 --- /dev/null +++ b/modules/drivers/hdf5/include/H5LTprivate.h @@ -0,0 +1,30 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef H5LTprivate_H +#define H5LTprivate_H + +/* High-level library internal header file */ +#include "H5HLprivate2.h" + +/* public LT prototypes */ +#include "H5LTpublic.h" + +H5_HLDLL herr_t H5LT_get_attribute_disk(hid_t obj_id, const char *attr_name, void *data); +H5_HLDLL herr_t H5LT_set_attribute_numerical(hid_t loc_id, const char *obj_name, const char *attr_name, + size_t size, hid_t type_id, const void *data); +H5_HLDLL herr_t H5LT_set_attribute_string(hid_t dset_id, const char *name, const char *buf); +H5_HLDLL char *H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, + bool no_user_buf); +H5_HLDLL hid_t H5LTyyparse(void); + +#endif diff --git a/modules/drivers/hdf5/source/H5LT.c b/modules/drivers/hdf5/source/H5LT.c new file mode 100644 index 000000000..d48f24008 --- /dev/null +++ b/modules/drivers/hdf5/source/H5LT.c @@ -0,0 +1,3343 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "H5LTprivate.h" + +/* For Lex and Yacc */ +#define COL 3 +#define LIMIT 512 +#define INCREMENT 1024 +#define TMP_LEN 256 +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +size_t input_len; +char *myinput; +size_t indent = 0; + +/* File Image operations + + A file image is a representation of an HDF5 file in a memory + buffer. In order to perform operations on an image in a similar way + to a file, the application buffer is copied to a FAPL buffer, which + in turn is copied to a VFD buffer. Buffer copying can decrease + performance, especially when using large file images. A solution to + this issue is to simulate the copying of the application buffer, + when actually the same buffer is used for the FAPL and the VFD. + This is implemented by using callbacks that simulate the standard + functions for memory management (additional callbacks are used for + the management of associated data structures). From the application + standpoint, a file handle can be obtained from a file image by using + the API routine H5LTopen_file_image(). This function takes a flag + argument that indicates the HDF5 library how to handle the given image; + several flag values can be combined by using the bitwise OR operator. + Valid flag values include: + + H5LT_FILE_IMAGE_OPEN_RW indicates the HDF5 library to open the file + image in read/write mode. Default is read-only mode. + + H5LT_FILE_IMAGE_DONT_COPY indicates the HDF5 library to not copy the + supplied user buffer; the same buffer will be handled by the FAPL and + the VFD driver. Default operation copies the user buffer to the FAPL and + VFD driver. + + H5LT_FILE_IMAGE_DONT_RELEASE indicates the HDF5 library to not release + the buffer handled by the FAPL and the VFD upon closing. This flag value + is only applicable when the flag value H5LT_FILE_IMAGE_DONT_COPY is set as + well. The application is responsible to release the image buffer. +*/ + +/* Data structure to pass application data to callbacks. */ +typedef struct { + void *app_image_ptr; /* Pointer to application buffer */ + size_t app_image_size; /* Size of application buffer */ + void *fapl_image_ptr; /* Pointer to FAPL buffer */ + size_t fapl_image_size; /* Size of FAPL buffer */ + int fapl_ref_count; /* Reference counter for FAPL buffer */ + void *vfd_image_ptr; /* Pointer to VFD buffer */ + size_t vfd_image_size; /* Size of VFD buffer */ + int vfd_ref_count; /* Reference counter for VFD buffer */ + unsigned flags; /* Flags indicate how the file image will */ + /* be open */ + int ref_count; /* Reference counter on udata struct */ +} H5LT_file_image_ud_t; + +/* callbacks prototypes for file image ops */ +static void *image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *udata); +static void *image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, + void *udata); +static void *image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *udata); +static herr_t image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *udata); +static void *udata_copy(void *udata); +static herr_t udata_free(void *udata); + +/* Definition of callbacks for file image operations. */ + +/*------------------------------------------------------------------------- + * Function: image_malloc + * + * Purpose: Simulates malloc() function to avoid copying file images. + * The application buffer is set to the buffer on only one FAPL. + * Then the FAPL buffer can be copied to other FAPL buffers or + * to only one VFD buffer. + * + * Return: Address of "allocated" buffer, if successful. Otherwise, it returns + * NULL. + * + *------------------------------------------------------------------------- + */ +static void * +image_malloc(size_t size, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + void *return_value = NULL; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch (file_image_op) { + /* the app buffer is "copied" to only one FAPL. Afterwards, FAPLs can be "copied" */ + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + if (udata->app_image_ptr == NULL) + goto out; + if (udata->app_image_size != size) + goto out; + if (udata->fapl_image_ptr != NULL) + goto out; + if (udata->fapl_image_size != 0) + goto out; + if (udata->fapl_ref_count != 0) + goto out; + + udata->fapl_image_ptr = udata->app_image_ptr; + udata->fapl_image_size = udata->app_image_size; + return_value = udata->fapl_image_ptr; + udata->fapl_ref_count++; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + if (udata->fapl_image_ptr == NULL) + goto out; + if (udata->fapl_image_size != size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + + return_value = udata->fapl_image_ptr; + udata->fapl_ref_count++; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + goto out; + + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + /* FAPL buffer is "copied" to only one VFD buffer */ + if (udata->vfd_image_ptr != NULL) + goto out; + if (udata->vfd_image_size != 0) + goto out; + if (udata->vfd_ref_count != 0) + goto out; + if (udata->fapl_image_ptr == NULL) + goto out; + if (udata->fapl_image_size != size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + + udata->vfd_image_ptr = udata->fapl_image_ptr; + udata->vfd_image_size = size; + udata->vfd_ref_count++; + return_value = udata->vfd_image_ptr; + break; + + /* added unused labels to shut the compiler up */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + default: + goto out; + } /* end switch */ + + return (return_value); + +out: + return NULL; +} /* end image_malloc() */ + +/*------------------------------------------------------------------------- + * Function: image_memcpy + * + * Purpose: Simulates memcpy() function to avoid copying file images. + * The image buffer can be set to only one FAPL buffer, and + * "copied" to only one VFD buffer. The FAPL buffer can be + * "copied" to other FAPLs buffers. + * + * Return: The address of the destination buffer, if successful. Otherwise, it + * returns NULL. + * + *------------------------------------------------------------------------- + */ +static void * +image_memcpy(void *dest, const void *src, size_t size, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch (file_image_op) { + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + if (dest != udata->fapl_image_ptr) + goto out; + if (src != udata->app_image_ptr) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (size != udata->app_image_size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + if (dest != udata->fapl_image_ptr) + goto out; + if (src != udata->fapl_image_ptr) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (udata->fapl_ref_count < 2) + goto out; + break; + + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + goto out; + + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + if (dest != udata->vfd_image_ptr) + goto out; + if (src != udata->fapl_image_ptr) + goto out; + if (size != udata->vfd_image_size) + goto out; + if (size != udata->fapl_image_size) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + if (udata->vfd_ref_count != 1) + goto out; + break; + + /* added unused labels to shut the compiler up */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + default: + goto out; + } /* end switch */ + + return (dest); + +out: + return NULL; +} /* end image_memcpy() */ + +/*------------------------------------------------------------------------- + * Function: image_realloc + * + * Purpose: Reallocates the shared application image buffer and updates data + * structures that manage buffer "copying". + * + * Return: Address of reallocated buffer, if successful. Otherwise, it returns + * NULL. + * + *------------------------------------------------------------------------- + */ +static void * +image_realloc(void *ptr, size_t size, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + void *return_value = NULL; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + /* realloc() is not allowed when the HDF5 library won't release the image + buffer because reallocation may change the address of the buffer. The + new address cannot be communicated to the application to release it. */ + if (udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE) + goto out; + + /* realloc() is not allowed if the image is open in read-only mode */ + if (!(udata->flags & H5LT_FILE_IMAGE_OPEN_RW)) + goto out; + + if (file_image_op == H5FD_FILE_IMAGE_OP_FILE_RESIZE) { + if (udata->vfd_image_ptr != ptr) + goto out; + + if (udata->vfd_ref_count != 1) + goto out; + + if (NULL == (udata->vfd_image_ptr = realloc(ptr, size))) + goto out; + + udata->vfd_image_size = size; + return_value = udata->vfd_image_ptr; + } /* end if */ + else + goto out; + + return (return_value); + +out: + return NULL; +} /* end image_realloc() */ + +/*------------------------------------------------------------------------- + * Function: image_free + * + * Purpose: Simulates deallocation of FAPL and VFD buffers by decreasing + * reference counters. Shared application buffer is actually + * deallocated if there are no outstanding references. + * + * Return: SUCCEED or FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +image_free(void *ptr, H5FD_file_image_op_t file_image_op, void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + + switch (file_image_op) { + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_CLOSE: + if (udata->fapl_image_ptr != ptr) + goto out; + if (udata->fapl_ref_count == 0) + goto out; + + udata->fapl_ref_count--; + + /* release the shared buffer only if indicated by the respective flag and there are no outstanding + * references */ + if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 && + !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) { + free(udata->fapl_image_ptr); + udata->app_image_ptr = NULL; + udata->fapl_image_ptr = NULL; + udata->vfd_image_ptr = NULL; + } /* end if */ + break; + + case H5FD_FILE_IMAGE_OP_FILE_CLOSE: + if (udata->vfd_image_ptr != ptr) + goto out; + if (udata->vfd_ref_count != 1) + goto out; + + udata->vfd_ref_count--; + + /* release the shared buffer only if indicated by the respective flag and there are no outstanding + * references */ + if (udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0 && + !(udata->flags & H5LT_FILE_IMAGE_DONT_RELEASE)) { + free(udata->vfd_image_ptr); + udata->app_image_ptr = NULL; + udata->fapl_image_ptr = NULL; + udata->vfd_image_ptr = NULL; + } /* end if */ + break; + + /* added unused labels to keep the compiler quite */ + case H5FD_FILE_IMAGE_OP_NO_OP: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_SET: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_COPY: + case H5FD_FILE_IMAGE_OP_PROPERTY_LIST_GET: + case H5FD_FILE_IMAGE_OP_FILE_OPEN: + case H5FD_FILE_IMAGE_OP_FILE_RESIZE: + default: + goto out; + } /* end switch */ + + return (SUCCEED); + +out: + return (FAIL); +} /* end image_free() */ + +/*------------------------------------------------------------------------- + * Function: udata_copy + * + * Purpose: Simulates the copying of the user data structure utilized in the + * management of the "copying" of file images. + * + * Return: Address of "newly allocated" structure, if successful. Otherwise, it + * returns NULL. + * + *------------------------------------------------------------------------- + */ +static void * +udata_copy(void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + if (udata->ref_count == 0) + goto out; + + udata->ref_count++; + + return (udata); + +out: + return NULL; +} /* end udata_copy */ + +/*------------------------------------------------------------------------- + * Function: udata_free + * + * Purpose: Simulates deallocation of the user data structure utilized in the + * management of the "copying" of file images. The data structure is + * actually deallocated when there are no outstanding references. + * + * Return: SUCCEED or FAIL + * + *------------------------------------------------------------------------- + */ +static herr_t +udata_free(void *_udata) +{ + H5LT_file_image_ud_t *udata = (H5LT_file_image_ud_t *)_udata; + + /* callback is only used if the application buffer is not actually copied */ + if (!(udata->flags & H5LT_FILE_IMAGE_DONT_COPY)) + goto out; + if (udata->ref_count == 0) + goto out; + + udata->ref_count--; + + /* checks that there are no references outstanding before deallocating udata */ + if (udata->ref_count == 0 && udata->fapl_ref_count == 0 && udata->vfd_ref_count == 0) + free(udata); + + return (SUCCEED); + +out: + return (FAIL); +} /* end udata_free */ + +/* End of callbacks definitions for file image operations */ + +/*------------------------------------------------------------------------- + * + * internal functions + * + *------------------------------------------------------------------------- + */ +static herr_t H5LT_get_attribute_mem(hid_t loc_id, const char *obj_name, const char *attr_name, + hid_t mem_type_id, void *data); + +/*------------------------------------------------------------------------- + * Function: H5LT_make_dataset + * + * Purpose: Creates and writes a dataset of a type tid + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +static herr_t +H5LT_make_dataset_numerical(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, hid_t tid, + const void *data) +{ + hid_t did = -1, sid = -1; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* Create the data space for the dataset. */ + if ((sid = H5Screate_simple(rank, dims, NULL)) < 0) + return -1; + + /* Create the dataset. */ + if ((did = H5Dcreate2(loc_id, dset_name, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + goto out; + + /* Write the dataset only if there is data to write */ + if (data) + if (H5Dwrite(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + goto out; + + /* End access to the dataset and release resources used by it. */ + if (H5Dclose(did) < 0) + return -1; + + /* Terminate access to the data space. */ + if (H5Sclose(sid) < 0) + return -1; + + return 0; + +out: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Sclose(sid); + } + H5E_END_TRY + return -1; +} + +/*------------------------------------------------------------------------- + * + * Public functions + * + *------------------------------------------------------------------------- + */ + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset + * + * Purpose: Creates and writes a dataset of a type tid + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, hid_t tid, + const void *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, tid, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_char + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_CHAR type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_char(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, const char *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_CHAR, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_short + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_SHORT type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_short(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, const short *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_SHORT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_int + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_INT type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_int(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, const int *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_INT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_long + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_LONG type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_long(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, const long *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_LONG, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_float + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_FLOAT type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_float(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, const float *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_FLOAT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_double + * + * Purpose: Creates and writes a dataset of H5T_NATIVE_DOUBLE type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_double(hid_t loc_id, const char *dset_name, int rank, const hsize_t *dims, + const double *data) +{ + return (H5LT_make_dataset_numerical(loc_id, dset_name, rank, dims, H5T_NATIVE_DOUBLE, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTmake_dataset_string + * + * Purpose: Creates and writes a dataset of H5T_C_S1 type + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTmake_dataset_string(hid_t loc_id, const char *dset_name, const char *buf) +{ + hid_t did = -1; + hid_t sid = -1; + hid_t tid = -1; + size_t size; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* create a string data type */ + if ((tid = H5Tcopy(H5T_C_S1)) < 0) + goto out; + + size = strlen(buf) + 1; /* extra null term */ + + if (H5Tset_size(tid, size) < 0) + goto out; + + if (H5Tset_strpad(tid, H5T_STR_NULLTERM) < 0) + goto out; + + /* Create the data space for the dataset. */ + if ((sid = H5Screate(H5S_SCALAR)) < 0) + goto out; + + /* Create the dataset. */ + if ((did = H5Dcreate2(loc_id, dset_name, tid, sid, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT)) < 0) + goto out; + + /* Write the dataset only if there is data to write */ + if (buf) + if (H5Dwrite(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) + goto out; + + /* close*/ + if (H5Dclose(did) < 0) + return -1; + if (H5Sclose(sid) < 0) + return -1; + if (H5Tclose(tid) < 0) + goto out; + + return 0; + +out: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Tclose(tid); + H5Sclose(sid); + } + H5E_END_TRY + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTopen_file_image + * + * Purpose: Open a user supplied file image using the core file driver. + * + * Return: File identifier, Failure: -1 + * + *------------------------------------------------------------------------- + */ +hid_t +H5LTopen_file_image(void *buf_ptr, size_t buf_size, unsigned flags) +{ + hid_t fapl = -1, file_id = -1; /* HDF5 identifiers */ + unsigned file_open_flags; /* Flags for image open */ + char file_name[64]; /* Filename buffer */ + size_t alloc_incr; /* Buffer allocation increment */ + size_t min_incr = 65536; /* Minimum buffer increment */ + double buf_prcnt = 0.1; /* Percentage of buffer size to set + as increment */ + static long file_name_counter; + H5FD_file_image_callbacks_t callbacks = {&image_malloc, &image_memcpy, &image_realloc, &image_free, + &udata_copy, &udata_free, (void *)NULL}; + + /* check arguments */ + if (buf_ptr == NULL) + goto out; + if (buf_size == 0) + goto out; + if (flags & (unsigned)~(H5LT_FILE_IMAGE_ALL)) + goto out; + + /* Create FAPL to transmit file image */ + if ((fapl = H5Pcreate(H5P_FILE_ACCESS)) < 0) + goto out; + + /* set allocation increment to a percentage of the supplied buffer size, or + * a pre-defined minimum increment value, whichever is larger + */ + if ((size_t)(buf_prcnt * (double)buf_size) > min_incr) + alloc_incr = (size_t)(buf_prcnt * (double)buf_size); + else + alloc_incr = min_incr; + + /* Configure FAPL to use the core file driver */ + if (H5Pset_fapl_core(fapl, alloc_incr, false) < 0) + goto out; + + /* Set callbacks for file image ops ONLY if the file image is NOT copied */ + if (flags & H5LT_FILE_IMAGE_DONT_COPY) { + H5LT_file_image_ud_t *udata; /* Pointer to udata structure */ + + /* Allocate buffer to communicate user data to callbacks */ + if (NULL == (udata = (H5LT_file_image_ud_t *)malloc(sizeof(H5LT_file_image_ud_t)))) + goto out; + + /* Initialize udata with info about app buffer containing file image and flags */ + udata->app_image_ptr = buf_ptr; + udata->app_image_size = buf_size; + udata->fapl_image_ptr = NULL; + udata->fapl_image_size = 0; + udata->fapl_ref_count = 0; + udata->vfd_image_ptr = NULL; + udata->vfd_image_size = 0; + udata->vfd_ref_count = 0; + udata->flags = flags; + udata->ref_count = 1; /* corresponding to the first FAPL */ + + /* copy address of udata into callbacks */ + callbacks.udata = (void *)udata; + + /* Set file image callbacks */ + if (H5Pset_file_image_callbacks(fapl, &callbacks) < 0) { + free(udata); + goto out; + } /* end if */ + } /* end if */ + + /* Assign file image in user buffer to FAPL */ + if (H5Pset_file_image(fapl, buf_ptr, buf_size) < 0) + goto out; + + /* set file open flags */ + if (flags & H5LT_FILE_IMAGE_OPEN_RW) + file_open_flags = H5F_ACC_RDWR; + else + file_open_flags = H5F_ACC_RDONLY; + + /* define a unique file name */ + snprintf(file_name, (sizeof(file_name) - 1), "file_image_%ld", file_name_counter++); + + /* Assign file image in FAPL to the core file driver */ + if ((file_id = H5Fopen(file_name, file_open_flags, fapl)) < 0) + goto out; + + /* Close FAPL */ + if (H5Pclose(fapl) < 0) + goto out; + + /* Return file identifier */ + return file_id; + +out: + H5E_BEGIN_TRY + { + H5Pclose(fapl); + } + H5E_END_TRY + return -1; +} /* end H5LTopen_file_image() */ + +/*------------------------------------------------------------------------- + * Function: H5LT_read_dataset + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +static herr_t +H5LT_read_dataset_numerical(hid_t loc_id, const char *dset_name, hid_t tid, void *data) +{ + hid_t did; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* Open the dataset. */ + if ((did = H5Dopen2(loc_id, dset_name, H5P_DEFAULT)) < 0) + return -1; + + /* Read */ + if (H5Dread(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, data) < 0) + goto out; + + /* End access to the dataset and release resources used by it. */ + if (H5Dclose(did)) + return -1; + + return 0; + +out: + H5Dclose(did); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset(hid_t loc_id, const char *dset_name, hid_t tid, void *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, tid, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_char + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_char(hid_t loc_id, const char *dset_name, char *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_CHAR, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_short + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_short(hid_t loc_id, const char *dset_name, short *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_SHORT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_int + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_int(hid_t loc_id, const char *dset_name, int *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_INT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_long + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_long(hid_t loc_id, const char *dset_name, long *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_LONG, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_float + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_float(hid_t loc_id, const char *dset_name, float *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_FLOAT, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_double + * + * Purpose: Reads a dataset from disk. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_double(hid_t loc_id, const char *dset_name, double *data) +{ + return (H5LT_read_dataset_numerical(loc_id, dset_name, H5T_NATIVE_DOUBLE, data)); +} + +/*------------------------------------------------------------------------- + * Function: H5LTread_dataset_string + * + * Purpose: Reads a dataset + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTread_dataset_string(hid_t loc_id, const char *dset_name, char *buf) +{ + hid_t did = -1; + hid_t tid = -1; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* Open the dataset. */ + if ((did = H5Dopen2(loc_id, dset_name, H5P_DEFAULT)) < 0) + return -1; + + if ((tid = H5Dget_type(did)) < 0) + goto out; + + /* Read */ + if (H5Dread(did, tid, H5S_ALL, H5S_ALL, H5P_DEFAULT, buf) < 0) + goto out; + + /* close */ + if (H5Dclose(did)) + goto out; + if (H5Tclose(tid)) + return -1; + + return 0; + +out: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Tclose(tid); + } + H5E_END_TRY + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_dataset_ndims + * + * Purpose: Gets the dimensionality of a dataset. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_dataset_ndims(hid_t loc_id, const char *dset_name, int *rank) +{ + hid_t did = -1; + hid_t sid = -1; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* Open the dataset. */ + if ((did = H5Dopen2(loc_id, dset_name, H5P_DEFAULT)) < 0) + return -1; + + /* Get the dataspace handle */ + if ((sid = H5Dget_space(did)) < 0) + goto out; + + /* Get rank */ + if ((*rank = H5Sget_simple_extent_ndims(sid)) < 0) + goto out; + + /* Terminate access to the dataspace */ + if (H5Sclose(sid) < 0) + goto out; + + /* End access to the dataset */ + if (H5Dclose(did)) + return -1; + + return 0; + +out: + H5E_BEGIN_TRY + { + H5Dclose(did); + H5Sclose(sid); + } + H5E_END_TRY + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_dataset_info + * + * Purpose: Gets information about a dataset. + * + * Return: Success: 0, Failure: -1 + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_dataset_info(hid_t loc_id, const char *dset_name, hsize_t *dims, H5T_class_t *type_class, + size_t *type_size) +{ + hid_t did = -1; + hid_t tid = -1; + hid_t sid = -1; + + /* check the arguments */ + if (dset_name == NULL) + return -1; + + /* open the dataset. */ + if ((did = H5Dopen2(loc_id, dset_name, H5P_DEFAULT)) < 0) + return -1; + + /* get an identifier for the datatype. */ + tid = H5Dget_type(did); + + /* get the class. */ + if (type_class != NULL) + *type_class = H5Tget_class(tid); + + /* get the size. */ + if (type_size != NULL) + *type_size = H5Tget_size(tid); + + if (dims != NULL) { + /* get the dataspace handle */ + if ((sid = H5Dget_space(did)) < 0) + goto out; + + /* get dimensions */ + if (H5Sget_simple_extent_dims(sid, dims, NULL) < 0) + goto out; + + /* terminate access to the dataspace */ + if (H5Sclose(sid) < 0) + goto out; + } /* end if */ + + /* release the datatype. */ + if (H5Tclose(tid)) + return -1; + + /* end access to the dataset */ + if (H5Dclose(did)) + return -1; + + return 0; + +out: + H5E_BEGIN_TRY + { + H5Tclose(tid); + H5Sclose(sid); + H5Dclose(did); + } + H5E_END_TRY + return -1; +} + +/*------------------------------------------------------------------------- + * Function: find_dataset + * + * Purpose: operator function used by H5LTfind_dataset + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +static herr_t +find_dataset(H5_ATTR_UNUSED hid_t loc_id, const char *name, H5_ATTR_UNUSED const H5L_info2_t *linfo, + void *op_data) +{ + /* Define a default zero value for return. This will cause the iterator to continue if + * the dataset is not found yet. + */ + int ret = 0; + + /* check the arguments */ + if (name == NULL) + return ret; + + /* Shut the compiler up */ + (void)loc_id; + (void)linfo; + + /* Define a positive value for return value if the dataset was found. This will + * cause the iterator to immediately return that positive value, + * indicating short-circuit success + */ + if (strncmp(name, (char *)op_data, strlen((char *)op_data)) == 0) + ret = 1; + + return ret; +} + +/*------------------------------------------------------------------------- + * Function: H5LTfind_dataset + * + * Purpose: Inquires if a dataset named dset_name exists attached + * to the object loc_id. + * + * Return: + * Success: The return value of the first operator that + * returns non-zero, or zero if all members were + * processed with no operator returning non-zero. + * + * Failure: Negative if something goes wrong within the + * library, or the negative value returned by one + * of the operators. + * + *------------------------------------------------------------------------- + */ +/* H5Literate wants a non-const pointer but we have a const pointer in the API + * call. It's safe to ignore this because we control the callback, don't + * modify the op_data buffer (i.e.: dset_name) during the traversal, and the + * library never modifies that buffer. + */ +H5_GCC_CLANG_DIAG_OFF("cast-qual") +herr_t +H5LTfind_dataset(hid_t loc_id, const char *dset_name) +{ + return H5Literate2(loc_id, H5_INDEX_NAME, H5_ITER_INC, 0, find_dataset, (void *)dset_name); +} +H5_GCC_CLANG_DIAG_ON("cast-qual") + +/*------------------------------------------------------------------------- + * + * Set attribute functions + * + *------------------------------------------------------------------------- + */ + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_string + * + * Purpose: Creates and writes a string attribute named attr_name and attaches + * it to the object specified by the name obj_name. + * + * Return: Success: 0, Failure: -1 + * + * Comments: If the attribute already exists, it is overwritten + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTset_attribute_string(hid_t loc_id, const char *obj_name, const char *attr_name, const char *attr_data) +{ + hid_t attr_type; + hid_t attr_space_id; + hid_t attr_id; + hid_t obj_id; + htri_t has_attr; + size_t attr_size; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + if (attr_data == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + return -1; + + /* Create the attribute */ + if ((attr_type = H5Tcopy(H5T_C_S1)) < 0) + goto out; + + attr_size = strlen(attr_data) + 1; /* extra null term */ + + if (H5Tset_size(attr_type, (size_t)attr_size) < 0) + goto out; + + if (H5Tset_strpad(attr_type, H5T_STR_NULLTERM) < 0) + goto out; + + if ((attr_space_id = H5Screate(H5S_SCALAR)) < 0) + goto out; + + /* Delete the attribute if it already exists */ + if ((has_attr = H5Aexists(obj_id, attr_name)) < 0) + goto out; + if (has_attr > 0) + if (H5Adelete(obj_id, attr_name) < 0) + goto out; + + /* Create and write the attribute */ + + if ((attr_id = H5Acreate2(obj_id, attr_name, attr_type, attr_space_id, H5P_DEFAULT, H5P_DEFAULT)) < 0) + goto out; + + if (H5Awrite(attr_id, attr_type, attr_data) < 0) + goto out; + + if (H5Aclose(attr_id) < 0) + goto out; + + if (H5Sclose(attr_space_id) < 0) + goto out; + + if (H5Tclose(attr_type) < 0) + goto out; + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + return -1; + + return 0; + +out: + + H5Oclose(obj_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LT_set_attribute_numerical + * + * Purpose: Private function used by H5LTset_attribute_int and H5LTset_attribute_float + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LT_set_attribute_numerical(hid_t loc_id, const char *obj_name, const char *attr_name, size_t size, + hid_t tid, const void *data) +{ + + hid_t obj_id, sid, attr_id; + hsize_t dim_size = size; + htri_t has_attr; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + return -1; + + /* Create the data space for the attribute. */ + if ((sid = H5Screate_simple(1, &dim_size, NULL)) < 0) + goto out; + + /* Delete the attribute if it already exists */ + if ((has_attr = H5Aexists(obj_id, attr_name)) < 0) + goto out; + if (has_attr > 0) + if (H5Adelete(obj_id, attr_name) < 0) + goto out; + + /* Create the attribute. */ + if ((attr_id = H5Acreate2(obj_id, attr_name, tid, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) + goto out; + + /* Write the attribute data. */ + if (H5Awrite(attr_id, tid, data) < 0) + goto out; + + /* Close the attribute. */ + if (H5Aclose(attr_id) < 0) + goto out; + + /* Close the dataspace. */ + if (H5Sclose(sid) < 0) + goto out; + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + return -1; + + return 0; + +out: + H5Oclose(obj_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_char + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_char(hid_t loc_id, const char *obj_name, const char *attr_name, const char *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_CHAR, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_uchar + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_uchar(hid_t loc_id, const char *obj_name, const char *attr_name, const unsigned char *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_UCHAR, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_short + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_short(hid_t loc_id, const char *obj_name, const char *attr_name, const short *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_SHORT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_ushort + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_ushort(hid_t loc_id, const char *obj_name, const char *attr_name, + const unsigned short *data, size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_USHORT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_int + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_int(hid_t loc_id, const char *obj_name, const char *attr_name, const int *data, size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_INT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_uint + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_uint(hid_t loc_id, const char *obj_name, const char *attr_name, const unsigned int *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_UINT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_long + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_long(hid_t loc_id, const char *obj_name, const char *attr_name, const long *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_LONG, data) < 0) + return -1; + + return 0; +} +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_long_long + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: This function was added to support attributes of type long long + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_long_long(hid_t loc_id, const char *obj_name, const char *attr_name, const long long *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_LLONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_ulong + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_ulong(hid_t loc_id, const char *obj_name, const char *attr_name, const unsigned long *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_ULONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_ullong + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTset_attribute_ullong(hid_t loc_id, const char *obj_name, const char *attr_name, + const unsigned long long *data, size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_ULLONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_float + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_float(hid_t loc_id, const char *obj_name, const char *attr_name, const float *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_FLOAT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTset_attribute_double + * + * Purpose: Create and write an attribute. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTset_attribute_double(hid_t loc_id, const char *obj_name, const char *attr_name, const double *data, + size_t size) +{ + + if (H5LT_set_attribute_numerical(loc_id, obj_name, attr_name, size, H5T_NATIVE_DOUBLE, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTfind_attribute + * + * Purpose: Checks if an attribute named attr_name exists attached to + * the object loc_id + * + * TODO: Overloading herr_t is not a great idea. This function either + * needs to be rewritten to take a Boolean out parameter in + * HDF5 2.0 or possibly even eliminated entirely as it simply + * wraps H5Aexists. + * + * Return: An htri_t value cast to herr_t + * Exists: Positive + * Does not exist: 0 + * Error: Negative + *------------------------------------------------------------------------- + */ +herr_t +H5LTfind_attribute(hid_t loc_id, const char *attr_name) +{ + return (herr_t)H5Aexists(loc_id, attr_name); +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_ndims + * + * Purpose: Gets the dimensionality of an attribute. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute_ndims(hid_t loc_id, const char *obj_name, const char *attr_name, int *rank) +{ + hid_t attr_id; + hid_t sid; + hid_t obj_id; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + return -1; + + /* Open the attribute. */ + if ((attr_id = H5Aopen(obj_id, attr_name, H5P_DEFAULT)) < 0) { + H5Oclose(obj_id); + return -1; + } + + /* Get the dataspace handle */ + if ((sid = H5Aget_space(attr_id)) < 0) + goto out; + + /* Get rank */ + if ((*rank = H5Sget_simple_extent_ndims(sid)) < 0) + goto out; + + /* Terminate access to the attribute */ + if (H5Sclose(sid) < 0) + goto out; + + /* End access to the attribute */ + if (H5Aclose(attr_id)) + goto out; + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + return -1; + + return 0; + +out: + H5Aclose(attr_id); + H5Oclose(obj_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_info + * + * Purpose: Gets information about an attribute. + * + * Return: Success: 0, Failure: -1 + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute_info(hid_t loc_id, const char *obj_name, const char *attr_name, hsize_t *dims, + H5T_class_t *type_class, size_t *type_size) +{ + hid_t attr_id; + hid_t tid; + hid_t sid; + hid_t obj_id; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + return -1; + + /* Open the attribute. */ + if ((attr_id = H5Aopen(obj_id, attr_name, H5P_DEFAULT)) < 0) { + H5Oclose(obj_id); + return -1; + } + + /* Get an identifier for the datatype. */ + tid = H5Aget_type(attr_id); + + /* Get the class. */ + *type_class = H5Tget_class(tid); + + /* Get the size. */ + *type_size = H5Tget_size(tid); + + /* Get the dataspace handle */ + if ((sid = H5Aget_space(attr_id)) < 0) + goto out; + + /* Get dimensions */ + if (H5Sget_simple_extent_dims(sid, dims, NULL) < 0) + goto out; + + /* Terminate access to the dataspace */ + if (H5Sclose(sid) < 0) + goto out; + + /* Release the datatype. */ + if (H5Tclose(tid)) + goto out; + + /* End access to the attribute */ + if (H5Aclose(attr_id)) + goto out; + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + return -1; + + return 0; + +out: + H5Tclose(tid); + H5Aclose(attr_id); + H5Oclose(obj_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LTtext_to_dtype + * + * Purpose: Convert DDL description to HDF5 data type. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +hid_t +H5LTtext_to_dtype(const char *text, H5LT_lang_t lang_type) +{ + hid_t type_id; + + /* check the arguments */ + if (text == NULL) + return -1; + + if (lang_type <= H5LT_LANG_ERR || lang_type >= H5LT_NO_LANG) + goto out; + + if (lang_type != H5LT_DDL) { + fprintf(stderr, "only DDL is supported for now.\n"); + goto out; + } + + input_len = strlen(text); + myinput = HDstrdup(text); + + if ((type_id = H5LTyyparse()) < 0) { + free(myinput); + goto out; + } + + free(myinput); + input_len = 0; + + return type_id; + +out: + return -1; +} + +/*------------------------------------------------------------------------- + * Function: realloc_and_append + * + * Purpose: Expand the buffer and append a string to it. + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static char * +realloc_and_append(bool _no_user_buf, size_t *len, char *buf, const char *str_to_add) +{ + size_t size_str_to_add, size_str; + + if (_no_user_buf) { + char *tmp_realloc; + + if (!buf) + goto out; + + /* If the buffer isn't big enough, reallocate it. Otherwise, go to do strcat. */ + if (str_to_add && ((ssize_t)(*len - (strlen(buf) + strlen(str_to_add) + 1)) < LIMIT)) { + *len += ((strlen(buf) + strlen(str_to_add) + 1) / INCREMENT + 1) * INCREMENT; + } + else if (!str_to_add && ((ssize_t)(*len - strlen(buf) - 1) < LIMIT)) { + *len += INCREMENT; + } + + tmp_realloc = (char *)realloc(buf, *len); + if (tmp_realloc == NULL) { + free(buf); + buf = NULL; + goto out; + } + else + buf = tmp_realloc; + } + + if (str_to_add) { + /* find the size of the buffer to add */ + size_str_to_add = strlen(str_to_add); + /* find the size of the current buffer */ + size_str = strlen(buf); + + /* Check to make sure the appended string does not + * extend past the allocated buffer; if it does then truncate the string + */ + if (size_str < *len - 1) { + if (size_str + size_str_to_add < *len - 1) { + strcat(buf, str_to_add); + } + else { + strncat(buf, str_to_add, (*len - 1) - size_str); + } + } + else { + buf[*len - 1] = '\0'; /* buffer is full, null terminate */ + } + } + + return buf; + +out: + return NULL; +} + +/*------------------------------------------------------------------------- + * Function: indentation + * + * Purpose: Print spaces for indentation + * + * Return: void + * + *------------------------------------------------------------------------- + */ +static char * +indentation(size_t x, char *str, bool no_u_buf, size_t *s_len) +{ + char tmp_str[TMP_LEN]; + + if (x < 80) { + memset(tmp_str, ' ', x); + tmp_str[x] = '\0'; + } + else + snprintf(tmp_str, TMP_LEN, "error: the indentation exceeds the number of cols."); + + if (!(str = realloc_and_append(no_u_buf, s_len, str, tmp_str))) + goto out; + + return str; + +out: + return NULL; +} + +/*------------------------------------------------------------------------- + * Function: print_enum + * + * Purpose: prints the enum data + * + * Return: Success: 0, Failure: -1 + * + *-----------------------------------------------------------------------*/ +static char * +print_enum(hid_t type, char *str, size_t *str_len, bool no_ubuf, size_t indt) +{ + char **name = NULL; /*member names */ + unsigned char *value = NULL; /*value array */ + int nmembs; /*number of members */ + char tmp_str[TMP_LEN]; + int nchars; /*number of output characters */ + hid_t super = -1; /*enum base integer type */ + hid_t native = -1; /*native integer data type */ + size_t super_size; /*enum base type size */ + size_t dst_size; /*destination value type size */ + int i; + + if ((nmembs = H5Tget_nmembers(type)) <= 0) + goto out; + + if ((super = H5Tget_super(type)) < 0) + goto out; + + /* Use buffer of INT or UNSIGNED INT to print enum values because + * we don't expect these values to be so big that INT or UNSIGNED + * INT can't hold. + */ + if (H5T_SGN_NONE == H5Tget_sign(super)) { + native = H5T_NATIVE_UINT; + } + else { + native = H5T_NATIVE_INT; + } + + super_size = H5Tget_size(super); + dst_size = H5Tget_size(native); + + /* Get the names and raw values of all members */ + name = (char **)calloc((size_t)nmembs, sizeof(char *)); + value = (unsigned char *)calloc((size_t)nmembs, MAX(dst_size, super_size)); + + for (i = 0; i < nmembs; i++) { + if ((name[i] = H5Tget_member_name(type, (unsigned)i)) == NULL) + goto out; + if (H5Tget_member_value(type, (unsigned)i, value + (size_t)i * super_size) < 0) + goto out; + } + + /* Convert values to native data type */ + if (native > 0) { + if (H5Tconvert(super, native, (size_t)nmembs, value, NULL, H5P_DEFAULT) < 0) + goto out; + } + + /* + * Sort members by increasing value + * ***not implemented yet*** + */ + + /* Print members */ + for (i = 0; i < nmembs; i++) { + if (!(str = indentation(indt + COL, str, no_ubuf, str_len))) + goto out; + nchars = snprintf(tmp_str, TMP_LEN, "\"%s\"", name[i]); + if (!(str = realloc_and_append(no_ubuf, str_len, str, tmp_str))) + goto out; + memset(tmp_str, ' ', (size_t)MAX(3, 19 - nchars) + 1); + tmp_str[MAX(3, 19 - nchars)] = '\0'; + if (!(str = realloc_and_append(no_ubuf, str_len, str, tmp_str))) + goto out; + + if (H5T_SGN_NONE == H5Tget_sign(native)) + snprintf(tmp_str, TMP_LEN, "%u", *((unsigned int *)((void *)(value + (size_t)i * dst_size)))); + else + snprintf(tmp_str, TMP_LEN, "%d", *((int *)((void *)(value + (size_t)i * dst_size)))); + if (!(str = realloc_and_append(no_ubuf, str_len, str, tmp_str))) + goto out; + + snprintf(tmp_str, TMP_LEN, ";\n"); + if (!(str = realloc_and_append(no_ubuf, str_len, str, tmp_str))) + goto out; + } + + /* Release resources */ + for (i = 0; i < nmembs; i++) + H5free_memory(name[i]); + + free(name); + free(value); + H5Tclose(super); + + return str; + +out: + + if (0 == nmembs) { + str = realloc_and_append(no_ubuf, str_len, str, "\n"); + assert((indt + 4) < TMP_LEN); + memset(tmp_str, ' ', (indt + 4) + 1); + tmp_str[(indt + 4)] = '\0'; + str = realloc_and_append(no_ubuf, str_len, str, tmp_str); + str = realloc_and_append(no_ubuf, str_len, str, " "); + } /* end if */ + + /* Release resources */ + if (name) { + for (i = 0; i < nmembs; i++) + if (name[i]) + free(name[i]); + free(name); + } /* end if */ + + if (value) + free(value); + + if (super >= 0) + H5Tclose(super); + + return NULL; +} + +/*------------------------------------------------------------------------- + * Function: H5LTdtype_to_text + * + * Purpose: Convert HDF5 data type to DDL description. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTdtype_to_text(hid_t dtype, char *str, H5LT_lang_t lang_type, size_t *len) +{ + size_t str_len = INCREMENT; + char *text_str = NULL; + herr_t ret = SUCCEED; + + if (lang_type <= H5LT_LANG_ERR || lang_type >= H5LT_NO_LANG) + goto out; + + if (len && !str) { + text_str = (char *)calloc(str_len, sizeof(char)); + text_str[0] = '\0'; + if (!(text_str = H5LT_dtype_to_text(dtype, text_str, lang_type, &str_len, 1))) + goto out; + *len = strlen(text_str) + 1; + if (text_str) + free(text_str); + text_str = NULL; + } + else if (len && str) { + if (!(H5LT_dtype_to_text(dtype, str, lang_type, len, 0))) + goto out; + str[*len - 1] = '\0'; + } + + return ret; + +out: + free(text_str); + + return FAIL; +} + +/*------------------------------------------------------------------------- + * Function: H5LT_dtype_to_text + * + * Purpose: Private function to convert HDF5 data type to DDL description. + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +char * +H5LT_dtype_to_text(hid_t dtype, char *dt_str, H5LT_lang_t lang, size_t *slen, bool no_user_buf) +{ + H5T_class_t tcls; + char tmp_str[TMP_LEN]; + int i; + + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, NULL))) + goto out; + + if (lang != H5LT_DDL) { + snprintf(dt_str, *slen, "only DDL is supported for now"); + goto out; + } + + if ((tcls = H5Tget_class(dtype)) < 0) + goto out; + + switch (tcls) { + case H5T_INTEGER: + case H5T_BITFIELD: + if (H5Tequal(dtype, H5T_STD_I8BE)) { + snprintf(dt_str, *slen, "H5T_STD_I8BE"); + } + else if (H5Tequal(dtype, H5T_STD_I8LE)) { + snprintf(dt_str, *slen, "H5T_STD_I8LE"); + } + else if (H5Tequal(dtype, H5T_STD_I16BE)) { + snprintf(dt_str, *slen, "H5T_STD_I16BE"); + } + else if (H5Tequal(dtype, H5T_STD_I16LE)) { + snprintf(dt_str, *slen, "H5T_STD_I16LE"); + } + else if (H5Tequal(dtype, H5T_STD_I32BE)) { + snprintf(dt_str, *slen, "H5T_STD_I32BE"); + } + else if (H5Tequal(dtype, H5T_STD_I32LE)) { + snprintf(dt_str, *slen, "H5T_STD_I32LE"); + } + else if (H5Tequal(dtype, H5T_STD_I64BE)) { + snprintf(dt_str, *slen, "H5T_STD_I64BE"); + } + else if (H5Tequal(dtype, H5T_STD_I64LE)) { + snprintf(dt_str, *slen, "H5T_STD_I64LE"); + } + else if (H5Tequal(dtype, H5T_STD_U8BE)) { + snprintf(dt_str, *slen, "H5T_STD_U8BE"); + } + else if (H5Tequal(dtype, H5T_STD_U8LE)) { + snprintf(dt_str, *slen, "H5T_STD_U8LE"); + } + else if (H5Tequal(dtype, H5T_STD_U16BE)) { + snprintf(dt_str, *slen, "H5T_STD_U16BE"); + } + else if (H5Tequal(dtype, H5T_STD_U16LE)) { + snprintf(dt_str, *slen, "H5T_STD_U16LE"); + } + else if (H5Tequal(dtype, H5T_STD_U32BE)) { + snprintf(dt_str, *slen, "H5T_STD_U32BE"); + } + else if (H5Tequal(dtype, H5T_STD_U32LE)) { + snprintf(dt_str, *slen, "H5T_STD_U32LE"); + } + else if (H5Tequal(dtype, H5T_STD_U64BE)) { + snprintf(dt_str, *slen, "H5T_STD_U64BE"); + } + else if (H5Tequal(dtype, H5T_STD_U64LE)) { + snprintf(dt_str, *slen, "H5T_STD_U64LE"); + } + else if (H5Tequal(dtype, H5T_NATIVE_SCHAR)) { + snprintf(dt_str, *slen, "H5T_NATIVE_SCHAR"); + } + else if (H5Tequal(dtype, H5T_NATIVE_UCHAR)) { + snprintf(dt_str, *slen, "H5T_NATIVE_UCHAR"); + } + else if (H5Tequal(dtype, H5T_NATIVE_SHORT)) { + snprintf(dt_str, *slen, "H5T_NATIVE_SHORT"); + } + else if (H5Tequal(dtype, H5T_NATIVE_USHORT)) { + snprintf(dt_str, *slen, "H5T_NATIVE_USHORT"); + } + else if (H5Tequal(dtype, H5T_NATIVE_INT)) { + snprintf(dt_str, *slen, "H5T_NATIVE_INT"); + } + else if (H5Tequal(dtype, H5T_NATIVE_UINT)) { + snprintf(dt_str, *slen, "H5T_NATIVE_UINT"); + } + else if (H5Tequal(dtype, H5T_NATIVE_LONG)) { + snprintf(dt_str, *slen, "H5T_NATIVE_LONG"); + } + else if (H5Tequal(dtype, H5T_NATIVE_ULONG)) { + snprintf(dt_str, *slen, "H5T_NATIVE_ULONG"); + } + else if (H5Tequal(dtype, H5T_NATIVE_LLONG)) { + snprintf(dt_str, *slen, "H5T_NATIVE_LLONG"); + } + else if (H5Tequal(dtype, H5T_NATIVE_ULLONG)) { + snprintf(dt_str, *slen, "H5T_NATIVE_ULLONG"); + } + else { + snprintf(dt_str, *slen, "undefined integer"); + } + + break; + case H5T_FLOAT: + if (H5Tequal(dtype, H5T_IEEE_F32BE)) { + snprintf(dt_str, *slen, "H5T_IEEE_F32BE"); + } + else if (H5Tequal(dtype, H5T_IEEE_F32LE)) { + snprintf(dt_str, *slen, "H5T_IEEE_F32LE"); + } + else if (H5Tequal(dtype, H5T_IEEE_F64BE)) { + snprintf(dt_str, *slen, "H5T_IEEE_F64BE"); + } + else if (H5Tequal(dtype, H5T_IEEE_F64LE)) { + snprintf(dt_str, *slen, "H5T_IEEE_F64LE"); + } + else if (H5Tequal(dtype, H5T_NATIVE_FLOAT)) { + snprintf(dt_str, *slen, "H5T_NATIVE_FLOAT"); + } + else if (H5Tequal(dtype, H5T_NATIVE_DOUBLE)) { + snprintf(dt_str, *slen, "H5T_NATIVE_DOUBLE"); + } + else if (H5Tequal(dtype, H5T_NATIVE_LDOUBLE)) { + snprintf(dt_str, *slen, "H5T_NATIVE_LDOUBLE"); + } + else { + snprintf(dt_str, *slen, "undefined float"); + } + + break; + case H5T_STRING: { + /* Make a copy of type in memory in case when DTYPE is on disk, the size + * will be bigger than in memory. This makes it easier to compare + * types in memory. */ + hid_t str_type; + H5T_order_t order; + hid_t tmp_type; + size_t size; + H5T_str_t str_pad; + H5T_cset_t cset; + htri_t is_vlstr; + + if ((tmp_type = H5Tcopy(dtype)) < 0) + goto out; + if ((size = H5Tget_size(tmp_type)) == 0) + goto out; + if ((str_pad = H5Tget_strpad(tmp_type)) < 0) + goto out; + if ((cset = H5Tget_cset(tmp_type)) < 0) + goto out; + if ((is_vlstr = H5Tis_variable_str(tmp_type)) < 0) + goto out; + + /* Print lead-in */ + snprintf(dt_str, *slen, "H5T_STRING {\n"); + indent += COL; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if (is_vlstr) + snprintf(tmp_str, TMP_LEN, "STRSIZE H5T_VARIABLE;\n"); + else + snprintf(tmp_str, TMP_LEN, "STRSIZE %d;\n", (int)size); + + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if (str_pad == H5T_STR_NULLTERM) + snprintf(tmp_str, TMP_LEN, "STRPAD H5T_STR_NULLTERM;\n"); + else if (str_pad == H5T_STR_NULLPAD) + snprintf(tmp_str, TMP_LEN, "STRPAD H5T_STR_NULLPAD;\n"); + else if (str_pad == H5T_STR_SPACEPAD) + snprintf(tmp_str, TMP_LEN, "STRPAD H5T_STR_SPACEPAD;\n"); + else + snprintf(tmp_str, TMP_LEN, "STRPAD H5T_STR_ERROR;\n"); + + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if (cset == H5T_CSET_ASCII) + snprintf(tmp_str, TMP_LEN, "CSET H5T_CSET_ASCII;\n"); + else if (cset == H5T_CSET_UTF8) + snprintf(tmp_str, TMP_LEN, "CSET H5T_CSET_UTF8;\n"); + else + snprintf(tmp_str, TMP_LEN, "CSET unknown;\n"); + + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + /* Reproduce a C type string */ + if ((str_type = H5Tcopy(H5T_C_S1)) < 0) + goto out; + if (is_vlstr) { + if (H5Tset_size(str_type, H5T_VARIABLE) < 0) + goto out; + } + else { + if (H5Tset_size(str_type, size) < 0) + goto out; + } + if (H5Tset_cset(str_type, cset) < 0) + goto out; + if (H5Tset_strpad(str_type, str_pad) < 0) + goto out; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + /* Check C variable-length string first. Are the two types equal? */ + if (H5Tequal(tmp_type, str_type)) { + snprintf(tmp_str, TMP_LEN, "CTYPE H5T_C_S1;\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + goto next; + } + + /* Change the endianness and see if they're equal. */ + if ((order = H5Tget_order(tmp_type)) < 0) + goto out; + if (order == H5T_ORDER_LE) { + if (H5Tset_order(str_type, H5T_ORDER_LE) < 0) + goto out; + } + else if (order == H5T_ORDER_BE) { + if (H5Tset_order(str_type, H5T_ORDER_BE) < 0) + goto out; + } + + if (H5Tequal(tmp_type, str_type)) { + snprintf(tmp_str, TMP_LEN, "CTYPE H5T_C_S1;\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + goto next; + } + + /* If not equal to C variable-length string, check Fortran type. + * Actually H5Tequal can't tell difference between H5T_C_S1 and + * H5T_FORTRAN_S1!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + if (H5Tclose(str_type) < 0) + goto out; + if ((str_type = H5Tcopy(H5T_FORTRAN_S1)) < 0) + goto out; + if (H5Tset_cset(str_type, cset) < 0) + goto out; + if (H5Tset_size(str_type, size) < 0) + goto out; + if (H5Tset_strpad(str_type, str_pad) < 0) + goto out; + + /* Are the two types equal? */ + if (H5Tequal(tmp_type, str_type)) { + snprintf(tmp_str, TMP_LEN, "CTYPE H5T_FORTRAN_S1;\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + goto next; + } + + /* Change the endianness and see if they're equal. */ + if ((order = H5Tget_order(tmp_type)) < 0) + goto out; + if (order == H5T_ORDER_LE) { + if (H5Tset_order(str_type, H5T_ORDER_LE) < 0) + goto out; + } + else if (order == H5T_ORDER_BE) { + if (H5Tset_order(str_type, H5T_ORDER_BE) < 0) + goto out; + } + + /* Are the two types equal? */ + if (H5Tequal(tmp_type, str_type)) { + snprintf(tmp_str, TMP_LEN, "CTYPE H5T_FORTRAN_S1;\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + goto next; + } + + /* Type doesn't match any of above. */ + snprintf(tmp_str, TMP_LEN, "CTYPE unknown_one_character_type;\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + +next: + H5Tclose(str_type); + H5Tclose(tmp_type); + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_OPAQUE: { + char *tag = NULL; + + /* Print lead-in */ + snprintf(dt_str, *slen, "H5T_OPAQUE {\n"); + indent += COL; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "OPQ_SIZE %lu;\n", (unsigned long)H5Tget_size(dtype)); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + tag = H5Tget_tag(dtype); + if (tag) { + snprintf(tmp_str, TMP_LEN, "OPQ_TAG \"%s\";\n", tag); + if (tag) + H5free_memory(tag); + tag = NULL; + } + else + snprintf(tmp_str, TMP_LEN, "OPQ_TAG \"\";\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_ENUM: { + hid_t super; + size_t super_len; + char *stmp = NULL; + + /* Print lead-in */ + snprintf(dt_str, *slen, "H5T_ENUM {\n"); + indent += COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if ((super = H5Tget_super(dtype)) < 0) + goto out; + if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0) + goto out; + stmp = (char *)calloc(super_len, sizeof(char)); + if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) { + free(stmp); + goto out; + } + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) { + free(stmp); + goto out; + } + + if (stmp) + free(stmp); + stmp = NULL; + + snprintf(tmp_str, TMP_LEN, ";\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + H5Tclose(super); + + if (!(dt_str = print_enum(dtype, dt_str, slen, no_user_buf, indent))) + goto out; + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_VLEN: { + hid_t super; + size_t super_len; + char *stmp = NULL; + + /* Print lead-in */ + snprintf(dt_str, *slen, "H5T_VLEN {\n"); + indent += COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if ((super = H5Tget_super(dtype)) < 0) + goto out; + if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0) + goto out; + stmp = (char *)calloc(super_len, sizeof(char)); + if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) { + free(stmp); + goto out; + } + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) { + free(stmp); + goto out; + } + + if (stmp) + free(stmp); + stmp = NULL; + snprintf(tmp_str, TMP_LEN, "\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + H5Tclose(super); + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_ARRAY: { + hid_t super; + size_t super_len; + char *stmp = NULL; + hsize_t dims[H5S_MAX_RANK]; + int ndims; + + /* Print lead-in */ + snprintf(dt_str, *slen, "H5T_ARRAY {\n"); + indent += COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + /* Get array information */ + if ((ndims = H5Tget_array_ndims(dtype)) < 0) + goto out; + if (H5Tget_array_dims2(dtype, dims) < 0) + goto out; + + /* Print array dimensions */ + for (i = 0; i < ndims; i++) { + snprintf(tmp_str, TMP_LEN, "[%d]", (int)dims[i]); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + } + snprintf(tmp_str, TMP_LEN, " "); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + if ((super = H5Tget_super(dtype)) < 0) + goto out; + if (H5LTdtype_to_text(super, NULL, lang, &super_len) < 0) + goto out; + stmp = (char *)calloc(super_len, sizeof(char)); + if (H5LTdtype_to_text(super, stmp, lang, &super_len) < 0) { + free(stmp); + goto out; + } + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, stmp))) { + free(stmp); + goto out; + } + if (stmp) + free(stmp); + stmp = NULL; + snprintf(tmp_str, TMP_LEN, "\n"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + H5Tclose(super); + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_COMPOUND: { + char *mname = NULL; + hid_t mtype; + size_t moffset; + H5T_class_t mclass; + size_t mlen; + char *mtmp = NULL; + int nmembs; + + if ((nmembs = H5Tget_nmembers(dtype)) < 0) + goto out; + + snprintf(dt_str, *slen, "H5T_COMPOUND {\n"); + indent += COL; + + for (i = 0; i < nmembs; i++) { + if ((mname = H5Tget_member_name(dtype, (unsigned)i)) == NULL) + goto out; + if ((mtype = H5Tget_member_type(dtype, (unsigned)i)) < 0) + goto out; + moffset = H5Tget_member_offset(dtype, (unsigned)i); + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + + if ((mclass = H5Tget_class(mtype)) < 0) + goto out; + if (H5T_COMPOUND == mclass) + indent += COL; + + if (H5LTdtype_to_text(mtype, NULL, lang, &mlen) < 0) + goto out; + mtmp = (char *)calloc(mlen, sizeof(char)); + if (H5LTdtype_to_text(mtype, mtmp, lang, &mlen) < 0) { + free(mtmp); + goto out; + } + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, mtmp))) { + free(mtmp); + goto out; + } + if (mtmp) + free(mtmp); + mtmp = NULL; + + if (H5T_COMPOUND == mclass) + indent -= COL; + + snprintf(tmp_str, TMP_LEN, " \"%s\"", mname); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + if (mname) + H5free_memory(mname); + mname = NULL; + + snprintf(tmp_str, TMP_LEN, " : %lu;\n", (unsigned long)moffset); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + } + + /* Print closing */ + indent -= COL; + if (!(dt_str = indentation(indent + COL, dt_str, no_user_buf, slen))) + goto out; + snprintf(tmp_str, TMP_LEN, "}"); + if (!(dt_str = realloc_and_append(no_user_buf, slen, dt_str, tmp_str))) + goto out; + + break; + } + case H5T_TIME: + snprintf(dt_str, *slen, "H5T_TIME: not yet implemented"); + break; + case H5T_NO_CLASS: + snprintf(dt_str, *slen, "H5T_NO_CLASS"); + break; + case H5T_REFERENCE: + if (H5Tequal(dtype, H5T_STD_REF_DSETREG) == true) { + snprintf(dt_str, *slen, " H5T_REFERENCE { H5T_STD_REF_DSETREG }"); + } + else { + snprintf(dt_str, *slen, " H5T_REFERENCE { H5T_STD_REF_OBJECT }"); + } + break; + case H5T_NCLASSES: + break; + default: + snprintf(dt_str, *slen, "unknown data type"); + } + + return dt_str; + +out: + return NULL; +} + +/*------------------------------------------------------------------------- + * + * Get attribute functions + * + *------------------------------------------------------------------------- + */ + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_string + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute_string(hid_t loc_id, const char *obj_name, const char *attr_name, char *data) +{ + /* identifiers */ + hid_t obj_id; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + return -1; + + /* Get the attribute */ + if (H5LT_get_attribute_disk(obj_id, attr_name, data) < 0) { + H5Oclose(obj_id); + return -1; + } + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_char + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_char(hid_t loc_id, const char *obj_name, const char *attr_name, char *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_CHAR, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_uchar + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_uchar(hid_t loc_id, const char *obj_name, const char *attr_name, unsigned char *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_UCHAR, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_short + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_short(hid_t loc_id, const char *obj_name, const char *attr_name, short *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_SHORT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_ushort + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_ushort(hid_t loc_id, const char *obj_name, const char *attr_name, unsigned short *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_USHORT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_int + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_int(hid_t loc_id, const char *obj_name, const char *attr_name, int *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_INT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_uint + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_uint(hid_t loc_id, const char *obj_name, const char *attr_name, unsigned int *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_UINT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_long + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_long(hid_t loc_id, const char *obj_name, const char *attr_name, long *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_LONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_long_long + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: This function was added to support INTEGER*8 Fortran types + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_long_long(hid_t loc_id, const char *obj_name, const char *attr_name, long long *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_LLONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_ulong + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_ulong(hid_t loc_id, const char *obj_name, const char *attr_name, unsigned long *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_ULONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_ullong + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LTget_attribute_ullong(hid_t loc_id, const char *obj_name, const char *attr_name, unsigned long long *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_ULLONG, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_float + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute_float(hid_t loc_id, const char *obj_name, const char *attr_name, float *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_FLOAT, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute_double + * + * Purpose: Reads an attribute named attr_name + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute_double(hid_t loc_id, const char *obj_name, const char *attr_name, double *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, H5T_NATIVE_DOUBLE, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * Function: H5LTget_attribute + * + * Purpose: Reads an attribute named attr_name with the memory type mem_type_id + * + * Return: Success: 0, Failure: -1 + * + * Comments: Private function + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LTget_attribute(hid_t loc_id, const char *obj_name, const char *attr_name, hid_t mem_type_id, void *data) +{ + /* Get the attribute */ + if (H5LT_get_attribute_mem(loc_id, obj_name, attr_name, mem_type_id, data) < 0) + return -1; + + return 0; +} + +/*------------------------------------------------------------------------- + * private functions + *------------------------------------------------------------------------- + */ + +/*------------------------------------------------------------------------- + * Function: H5LT_get_attribute_mem + * + * Purpose: Reads an attribute named attr_name with the memory type mem_type_id + * + * Return: Success: 0, Failure: -1 + * + * Comments: Private function + * + *------------------------------------------------------------------------- + */ + +static herr_t +H5LT_get_attribute_mem(hid_t loc_id, const char *obj_name, const char *attr_name, hid_t mem_type_id, + void *data) +{ + /* identifiers */ + hid_t obj_id = -1; + hid_t attr_id = -1; + + /* check the arguments */ + if (obj_name == NULL) + return -1; + if (attr_name == NULL) + return -1; + + /* Open the object */ + if ((obj_id = H5Oopen(loc_id, obj_name, H5P_DEFAULT)) < 0) + goto out; + + if ((attr_id = H5Aopen(obj_id, attr_name, H5P_DEFAULT)) < 0) + goto out; + + if (H5Aread(attr_id, mem_type_id, data) < 0) + goto out; + + if (H5Aclose(attr_id) < 0) + goto out; + attr_id = -1; + + /* Close the object */ + if (H5Oclose(obj_id) < 0) + goto out; + obj_id = -1; + + return 0; + +out: + if (obj_id > 0) + H5Oclose(obj_id); + if (attr_id > 0) + H5Aclose(attr_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LT_get_attribute_disk + * + * Purpose: Reads an attribute named attr_name with the datatype stored on disk + * + * Return: Success: 0, Failure: -1 + * + * Comments: + * + *------------------------------------------------------------------------- + */ + +herr_t +H5LT_get_attribute_disk(hid_t loc_id, const char *attr_name, void *attr_out) +{ + /* identifiers */ + hid_t attr_id; + hid_t attr_type; + + if ((attr_id = H5Aopen(loc_id, attr_name, H5P_DEFAULT)) < 0) + return -1; + + if ((attr_type = H5Aget_type(attr_id)) < 0) + goto out; + + if (H5Aread(attr_id, attr_type, attr_out) < 0) + goto out; + + if (H5Tclose(attr_type) < 0) + goto out; + + if (H5Aclose(attr_id) < 0) + return -1; + + return 0; + +out: + H5Tclose(attr_type); + H5Aclose(attr_id); + return -1; +} + +/*------------------------------------------------------------------------- + * Function: H5LT_set_attribute_string + * + * Purpose: creates and writes an attribute named NAME to the dataset DSET_ID + * + * Return: FAIL on error, SUCCESS on success + * + * Comments: + * + *------------------------------------------------------------------------- + */ +herr_t +H5LT_set_attribute_string(hid_t dset_id, const char *name, const char *buf) +{ + hid_t tid; + hid_t sid = -1; + hid_t aid = -1; + htri_t has_attr; + size_t size; + + /* Delete the attribute if it already exists */ + if ((has_attr = H5Aexists(dset_id, name)) < 0) + return FAIL; + if (has_attr > 0) + if (H5Adelete(dset_id, name) < 0) + return FAIL; + + /*------------------------------------------------------------------------- + * create the attribute type + *------------------------------------------------------------------------- + */ + if ((tid = H5Tcopy(H5T_C_S1)) < 0) + return FAIL; + + size = strlen(buf) + 1; /* extra null term */ + + if (H5Tset_size(tid, (size_t)size) < 0) + goto out; + + if (H5Tset_strpad(tid, H5T_STR_NULLTERM) < 0) + goto out; + + if ((sid = H5Screate(H5S_SCALAR)) < 0) + goto out; + + /*------------------------------------------------------------------------- + * create and write the attribute + *------------------------------------------------------------------------- + */ + if ((aid = H5Acreate2(dset_id, name, tid, sid, H5P_DEFAULT, H5P_DEFAULT)) < 0) + goto out; + + if (H5Awrite(aid, tid, buf) < 0) + goto out; + + if (H5Aclose(aid) < 0) + goto out; + + if (H5Sclose(sid) < 0) + goto out; + + if (H5Tclose(tid) < 0) + goto out; + + return SUCCEED; + + /* error zone */ +out: + H5E_BEGIN_TRY + { + H5Aclose(aid); + H5Tclose(tid); + H5Sclose(sid); + } + H5E_END_TRY + return FAIL; +} + +htri_t +H5LTpath_valid(hid_t loc_id, const char *path, hbool_t check_object_valid) +{ + char *tmp_path = NULL; /* Temporary copy of the path */ + char *curr_name; /* Pointer to current component of path name */ + char *delimit; /* Pointer to path delimiter during traversal */ + H5I_type_t obj_type; + htri_t link_exists, obj_exists; + size_t path_length; + htri_t ret_value; + + /* Initialize */ + ret_value = false; + + /* check the arguments */ + if (path == NULL) { + ret_value = FAIL; + goto done; + } + + /* Find the type of loc_id */ + if ((obj_type = H5Iget_type(loc_id)) == H5I_BADID) { + ret_value = FAIL; + goto done; + } + + /* Find the length of the path */ + path_length = strlen(path); + + /* Check if the identifier is the object itself, i.e. path is '.' */ + if (strncmp(path, ".", path_length) == 0) { + if (check_object_valid) { + obj_exists = H5Oexists_by_name(loc_id, path, H5P_DEFAULT); + ret_value = obj_exists; + goto done; + } + else { + ret_value = true; /* Since the object is the identifier itself, + * we can only check if loc_id is a valid type */ + goto done; + } + } + + /* Duplicate the path to use */ + if (NULL == (tmp_path = HDstrdup(path))) { + ret_value = FAIL; + goto done; + } + + curr_name = tmp_path; + + /* check if absolute pathname */ + if (strncmp(path, "/", 1) == 0) + curr_name++; + + /* check if relative path name starts with "./" */ + if (strncmp(path, "./", 2) == 0) + curr_name += 2; + + while ((delimit = strchr(curr_name, '/')) != NULL) { + /* Change the delimiter to terminate the string */ + *delimit = '\0'; + + obj_exists = false; + if ((link_exists = H5Lexists(loc_id, tmp_path, H5P_DEFAULT)) < 0) { + ret_value = FAIL; + goto done; + } + + /* If target link does not exist then no reason to + * continue checking the path */ + if (link_exists != true) { + ret_value = false; + goto done; + } + + /* Determine if link resolves to an actual object */ + if ((obj_exists = H5Oexists_by_name(loc_id, tmp_path, H5P_DEFAULT)) < 0) { + ret_value = FAIL; + goto done; + } + + if (obj_exists != true) + break; + + /* Change the delimiter back to '/' */ + *delimit = '/'; + + /* Advance the pointer in the path to the start of the next component */ + curr_name = delimit + 1; + + } /* end while */ + + /* Should be pointing to the last component in the path name now... */ + + /* Check if link does not exist */ + if ((link_exists = H5Lexists(loc_id, tmp_path, H5P_DEFAULT)) < 0) { + ret_value = FAIL; + } + else { + ret_value = link_exists; + /* Determine if link resolves to an actual object for check_object_valid true */ + if (check_object_valid == true && link_exists == true) { + if ((obj_exists = H5Oexists_by_name(loc_id, tmp_path, H5P_DEFAULT)) < 0) { + ret_value = FAIL; + } + else { + ret_value = obj_exists; + } + } + } + +done: + if (tmp_path != NULL) + free(tmp_path); + + return ret_value; +} diff --git a/modules/drivers/hdf5/source/H5LTanalyze.c b/modules/drivers/hdf5/source/H5LTanalyze.c new file mode 100644 index 000000000..8890b8e48 --- /dev/null +++ b/modules/drivers/hdf5/source/H5LTanalyze.c @@ -0,0 +1,2582 @@ +#if defined (__GNUC__) +#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wimplicit-function-declaration" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wnested-externs" +#pragma GCC diagnostic ignored "-Wold-style-definition" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#if !defined (__clang__) +#pragma GCC diagnostic ignored "-Wlarger-than=" +#pragma GCC diagnostic ignored "-Wsuggest-attribute=const" +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#endif +#pragma GCC diagnostic ignored "-Wswitch-default" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-macros" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 600 +#pragma GCC diagnostic ignored "-Wnull-dereference" +#endif +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif +#line 2 "hl/src//H5LTanalyze.c" +/* Quiet warnings about integer type macro redefinitions on Visual Studio + * (MSVC doesn't define STDC_VERSION, but has inttypes.h). This is an + * issue that is apparently fixed in flex 2.6.5. + */ +#include + +#line 9 "hl/src//H5LTanalyze.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer H5LTyy_create_buffer +#define yy_delete_buffer H5LTyy_delete_buffer +#define yy_scan_buffer H5LTyy_scan_buffer +#define yy_scan_string H5LTyy_scan_string +#define yy_scan_bytes H5LTyy_scan_bytes +#define yy_init_buffer H5LTyy_init_buffer +#define yy_flush_buffer H5LTyy_flush_buffer +#define yy_load_buffer_state H5LTyy_load_buffer_state +#define yy_switch_to_buffer H5LTyy_switch_to_buffer +#define yypush_buffer_state H5LTyypush_buffer_state +#define yypop_buffer_state H5LTyypop_buffer_state +#define yyensure_buffer_stack H5LTyyensure_buffer_stack +#define yy_flex_debug H5LTyy_flex_debug +#define yyin H5LTyyin +#define yyleng H5LTyyleng +#define yylex H5LTyylex +#define yylineno H5LTyylineno +#define yyout H5LTyyout +#define yyrestart H5LTyyrestart +#define yytext H5LTyytext +#define yywrap H5LTyywrap +#define yyalloc H5LTyyalloc +#define yyrealloc H5LTyyrealloc +#define yyfree H5LTyyfree + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +#ifdef yy_create_buffer +#define H5LTyy_create_buffer_ALREADY_DEFINED +#else +#define yy_create_buffer H5LTyy_create_buffer +#endif + +#ifdef yy_delete_buffer +#define H5LTyy_delete_buffer_ALREADY_DEFINED +#else +#define yy_delete_buffer H5LTyy_delete_buffer +#endif + +#ifdef yy_scan_buffer +#define H5LTyy_scan_buffer_ALREADY_DEFINED +#else +#define yy_scan_buffer H5LTyy_scan_buffer +#endif + +#ifdef yy_scan_string +#define H5LTyy_scan_string_ALREADY_DEFINED +#else +#define yy_scan_string H5LTyy_scan_string +#endif + +#ifdef yy_scan_bytes +#define H5LTyy_scan_bytes_ALREADY_DEFINED +#else +#define yy_scan_bytes H5LTyy_scan_bytes +#endif + +#ifdef yy_init_buffer +#define H5LTyy_init_buffer_ALREADY_DEFINED +#else +#define yy_init_buffer H5LTyy_init_buffer +#endif + +#ifdef yy_flush_buffer +#define H5LTyy_flush_buffer_ALREADY_DEFINED +#else +#define yy_flush_buffer H5LTyy_flush_buffer +#endif + +#ifdef yy_load_buffer_state +#define H5LTyy_load_buffer_state_ALREADY_DEFINED +#else +#define yy_load_buffer_state H5LTyy_load_buffer_state +#endif + +#ifdef yy_switch_to_buffer +#define H5LTyy_switch_to_buffer_ALREADY_DEFINED +#else +#define yy_switch_to_buffer H5LTyy_switch_to_buffer +#endif + +#ifdef yypush_buffer_state +#define H5LTyypush_buffer_state_ALREADY_DEFINED +#else +#define yypush_buffer_state H5LTyypush_buffer_state +#endif + +#ifdef yypop_buffer_state +#define H5LTyypop_buffer_state_ALREADY_DEFINED +#else +#define yypop_buffer_state H5LTyypop_buffer_state +#endif + +#ifdef yyensure_buffer_stack +#define H5LTyyensure_buffer_stack_ALREADY_DEFINED +#else +#define yyensure_buffer_stack H5LTyyensure_buffer_stack +#endif + +#ifdef yylex +#define H5LTyylex_ALREADY_DEFINED +#else +#define yylex H5LTyylex +#endif + +#ifdef yyrestart +#define H5LTyyrestart_ALREADY_DEFINED +#else +#define yyrestart H5LTyyrestart +#endif + +#ifdef yylex_init +#define H5LTyylex_init_ALREADY_DEFINED +#else +#define yylex_init H5LTyylex_init +#endif + +#ifdef yylex_init_extra +#define H5LTyylex_init_extra_ALREADY_DEFINED +#else +#define yylex_init_extra H5LTyylex_init_extra +#endif + +#ifdef yylex_destroy +#define H5LTyylex_destroy_ALREADY_DEFINED +#else +#define yylex_destroy H5LTyylex_destroy +#endif + +#ifdef yyget_debug +#define H5LTyyget_debug_ALREADY_DEFINED +#else +#define yyget_debug H5LTyyget_debug +#endif + +#ifdef yyset_debug +#define H5LTyyset_debug_ALREADY_DEFINED +#else +#define yyset_debug H5LTyyset_debug +#endif + +#ifdef yyget_extra +#define H5LTyyget_extra_ALREADY_DEFINED +#else +#define yyget_extra H5LTyyget_extra +#endif + +#ifdef yyset_extra +#define H5LTyyset_extra_ALREADY_DEFINED +#else +#define yyset_extra H5LTyyset_extra +#endif + +#ifdef yyget_in +#define H5LTyyget_in_ALREADY_DEFINED +#else +#define yyget_in H5LTyyget_in +#endif + +#ifdef yyset_in +#define H5LTyyset_in_ALREADY_DEFINED +#else +#define yyset_in H5LTyyset_in +#endif + +#ifdef yyget_out +#define H5LTyyget_out_ALREADY_DEFINED +#else +#define yyget_out H5LTyyget_out +#endif + +#ifdef yyset_out +#define H5LTyyset_out_ALREADY_DEFINED +#else +#define yyset_out H5LTyyset_out +#endif + +#ifdef yyget_leng +#define H5LTyyget_leng_ALREADY_DEFINED +#else +#define yyget_leng H5LTyyget_leng +#endif + +#ifdef yyget_text +#define H5LTyyget_text_ALREADY_DEFINED +#else +#define yyget_text H5LTyyget_text +#endif + +#ifdef yyget_lineno +#define H5LTyyget_lineno_ALREADY_DEFINED +#else +#define yyget_lineno H5LTyyget_lineno +#endif + +#ifdef yyset_lineno +#define H5LTyyset_lineno_ALREADY_DEFINED +#else +#define yyset_lineno H5LTyyset_lineno +#endif + +#ifdef yywrap +#define H5LTyywrap_ALREADY_DEFINED +#else +#define yywrap H5LTyywrap +#endif + +#ifdef yyalloc +#define H5LTyyalloc_ALREADY_DEFINED +#else +#define yyalloc H5LTyyalloc +#endif + +#ifdef yyrealloc +#define H5LTyyrealloc_ALREADY_DEFINED +#else +#define yyrealloc H5LTyyrealloc +#endif + +#ifdef yyfree +#define H5LTyyfree_ALREADY_DEFINED +#else +#define yyfree H5LTyyfree +#endif + +#ifdef yytext +#define H5LTyytext_ALREADY_DEFINED +#else +#define yytext H5LTyytext +#endif + +#ifdef yyleng +#define H5LTyyleng_ALREADY_DEFINED +#else +#define yyleng H5LTyyleng +#endif + +#ifdef yyin +#define H5LTyyin_ALREADY_DEFINED +#else +#define yyin H5LTyyin +#endif + +#ifdef yyout +#define H5LTyyout_ALREADY_DEFINED +#else +#define yyout H5LTyyout +#endif + +#ifdef yy_flex_debug +#define H5LTyy_flex_debug_ALREADY_DEFINED +#else +#define yy_flex_debug H5LTyy_flex_debug +#endif + +#ifdef yylineno +#define H5LTyylineno_ALREADY_DEFINED +#else +#define yylineno H5LTyylineno +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an + * integer in range [0..255] for use as an array index. + */ +#define YY_SC_TO_UI(c) ((YY_CHAR) (c)) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +extern int yyleng; + +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + #define YY_LINENO_REWIND_TO(ptr) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = NULL; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = NULL; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart ( FILE *input_file ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); +void yy_delete_buffer ( YY_BUFFER_STATE b ); +void yy_flush_buffer ( YY_BUFFER_STATE b ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer ); +void yypop_buffer_state ( void ); + +static void yyensure_buffer_stack ( void ); +static void yy_load_buffer_state ( void ); +static void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +#define YY_FLUSH_BUFFER yy_flush_buffer( YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len ); + +void *yyalloc ( yy_size_t ); +void *yyrealloc ( void *, yy_size_t ); +void yyfree ( void * ); + +#define yy_new_buffer yy_create_buffer +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + yyensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + yy_create_buffer( yyin, YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ +typedef flex_uint8_t YY_CHAR; + +FILE *yyin = NULL, *yyout = NULL; + +typedef int yy_state_type; + +extern int yylineno; +int yylineno = 1; + +extern char *yytext; +#ifdef yytext_ptr +#undef yytext_ptr +#endif +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state ( void ); +static yy_state_type yy_try_NUL_trans ( yy_state_type current_state ); +static int yy_get_next_buffer ( void ); +static void yynoreturn yy_fatal_error ( const char* msg ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; +#define YY_NUM_RULES 64 +#define YY_END_OF_BUFFER 65 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static const flex_int16_t yy_accept[275] = + { 0, + 63, 63, 65, 64, 63, 64, 55, 61, 62, 64, + 64, 64, 64, 59, 60, 57, 58, 63, 0, 55, + 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, + 0, 38, 0, 0, 0, 0, 0, 39, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 37, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 54, 36, 0, 0, 0, 45, 49, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 53, 50, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 2, 0, 0, 0, 0, 0, 0, 9, 10, 0, + 0, 47, 0, 44, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 3, 4, 5, 6, 7, 8, 11, 12, + 13, 14, 15, 16, 0, 0, 0, 43, 46, 28, + 29, 30, 31, 0, 0, 0, 22, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 24, 0, 0, 0, 23, + 0, 0, 0, 41, 0, 0, 0, 32, 0, 26, + 18, 20, 19, 0, 25, 0, 40, 42, 33, 0, + 27, 21, 34, 0 + } ; + +static const YY_CHAR yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 3, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 4, 5, 6, + 7, 8, 9, 10, 4, 11, 4, 12, 13, 1, + 1, 1, 1, 1, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 1, 1, 23, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 33, 1, 1, 34, 35, + 36, 1, 37, 1, 38, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 39, 1, 40, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static const YY_CHAR yy_meta[41] = + { 0, + 1, 1, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + } ; + +static const flex_int16_t yy_base[277] = + { 0, + 0, 0, 299, 300, 296, 0, 0, 300, 300, 11, + 288, 269, 264, 300, 300, 300, 300, 292, 290, 0, + 274, 257, 259, 261, 259, 300, 256, 259, 247, 246, + 16, 300, 265, 33, 14, 268, 259, 300, 251, 24, + 254, 252, 259, 262, 248, 243, 34, 251, 258, 254, + 235, 240, 244, 249, 236, 233, 235, 245, 231, 247, + 36, 231, 241, 223, 237, 300, 238, 241, 227, 222, + 247, 227, 219, 231, 226, 219, 208, 34, 223, 219, + 225, 300, 300, 208, 215, 202, 300, 300, 210, 200, + 204, 204, 38, 210, 39, 220, 300, 300, 300, 201, + + 47, 218, 212, 212, 211, 66, 73, 208, 195, 199, + 210, 199, 193, 191, 196, 75, 182, 300, 209, 212, + 209, 52, 206, 209, 206, 66, 300, 190, 198, 188, + 193, 193, 189, 169, 200, 197, 74, 71, 72, 77, + 186, 185, 84, 86, 87, 184, 183, 177, 183, 180, + 300, 175, 185, 165, 88, 90, 173, 167, 169, 166, + 91, 99, 96, 172, 171, 170, 169, 168, 167, 300, + 300, 166, 165, 164, 163, 162, 161, 300, 300, 94, + 160, 300, 155, 300, 171, 157, 156, 155, 154, 157, + 138, 143, 137, 141, 140, 140, 143, 137, 141, 136, + + 101, 139, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 145, 140, 130, 300, 300, 300, + 300, 300, 300, 127, 140, 140, 300, 121, 127, 131, + 136, 120, 134, 116, 120, 120, 118, 126, 113, 127, + 300, 117, 108, 123, 117, 300, 107, 104, 105, 300, + 108, 112, 102, 300, 105, 106, 104, 300, 93, 300, + 300, 300, 300, 78, 300, 57, 300, 300, 300, 56, + 300, 300, 300, 300, 127, 65 + } ; + +static const flex_int16_t yy_def[277] = + { 0, + 274, 1, 274, 274, 274, 275, 276, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 275, 276, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 0, 274, 274 + } ; + +static const flex_int16_t yy_nxt[341] = + { 0, + 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, + 7, 8, 9, 4, 4, 10, 4, 4, 4, 4, + 11, 4, 4, 4, 4, 12, 4, 4, 4, 13, + 4, 4, 4, 4, 4, 14, 15, 4, 16, 17, + 21, 22, 36, 48, 49, 37, 39, 62, 40, 53, + 41, 42, 77, 54, 43, 94, 63, 44, 45, 106, + 113, 55, 46, 109, 78, 47, 141, 20, 110, 107, + 119, 95, 120, 273, 142, 121, 122, 123, 114, 124, + 146, 135, 125, 126, 136, 164, 166, 272, 147, 157, + 158, 168, 159, 165, 167, 160, 161, 271, 172, 169, + + 174, 176, 186, 162, 188, 163, 173, 194, 175, 177, + 187, 199, 189, 195, 197, 270, 196, 200, 201, 198, + 215, 269, 268, 235, 216, 202, 236, 19, 267, 19, + 266, 265, 264, 263, 262, 261, 260, 259, 258, 257, + 256, 255, 254, 253, 252, 251, 250, 249, 248, 247, + 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, + 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, + 224, 223, 222, 221, 220, 219, 218, 217, 214, 213, + 212, 211, 210, 209, 208, 207, 206, 205, 204, 203, + 193, 192, 191, 190, 185, 184, 183, 182, 181, 180, + + 179, 178, 171, 170, 156, 155, 154, 153, 152, 151, + 150, 149, 148, 145, 144, 143, 140, 139, 138, 137, + 134, 133, 132, 131, 130, 129, 128, 127, 118, 117, + 116, 115, 112, 111, 108, 105, 104, 103, 102, 101, + 100, 99, 98, 97, 96, 93, 92, 91, 90, 89, + 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, + 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, + 66, 65, 64, 61, 60, 59, 58, 57, 56, 52, + 51, 50, 38, 35, 34, 33, 32, 31, 30, 29, + 28, 27, 26, 18, 25, 24, 23, 18, 274, 3, + + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274 + } ; + +static const flex_int16_t yy_chk[341] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 10, 10, 31, 35, 35, 31, 34, 47, 34, 40, + 34, 34, 61, 40, 34, 78, 47, 34, 34, 93, + 101, 40, 34, 95, 61, 34, 122, 276, 95, 93, + 106, 78, 106, 270, 122, 106, 106, 107, 101, 107, + 126, 116, 107, 107, 116, 138, 139, 266, 126, 137, + 137, 140, 137, 138, 139, 137, 137, 264, 143, 140, + + 144, 145, 155, 137, 156, 137, 143, 161, 144, 145, + 155, 163, 156, 161, 162, 259, 161, 163, 163, 162, + 180, 257, 256, 201, 180, 163, 201, 275, 255, 275, + 253, 252, 251, 249, 248, 247, 245, 244, 243, 242, + 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, + 230, 229, 228, 226, 225, 224, 217, 216, 215, 202, + 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, + 190, 189, 188, 187, 186, 185, 183, 181, 177, 176, + 175, 174, 173, 172, 169, 168, 167, 166, 165, 164, + 160, 159, 158, 157, 154, 153, 152, 150, 149, 148, + + 147, 146, 142, 141, 136, 135, 134, 133, 132, 131, + 130, 129, 128, 125, 124, 123, 121, 120, 119, 117, + 115, 114, 113, 112, 111, 110, 109, 108, 105, 104, + 103, 102, 100, 96, 94, 92, 91, 90, 89, 86, + 85, 84, 81, 80, 79, 77, 76, 75, 74, 73, + 72, 71, 70, 69, 68, 67, 65, 64, 63, 62, + 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, + 50, 49, 48, 46, 45, 44, 43, 42, 41, 39, + 37, 36, 33, 30, 29, 28, 27, 25, 24, 23, + 22, 21, 19, 18, 13, 12, 11, 5, 3, 274, + + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274, + 274, 274, 274, 274, 274, 274, 274, 274, 274, 274 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int yy_flex_debug; +int yy_flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "hl/src//H5LTanalyze.l" +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * Copyright by The HDF Group. * + * All rights reserved. * + * * + * This file is part of HDF5. The full HDF5 copyright notice, including * + * terms governing use, modification, and redistribution, is contained in * + * the COPYING file, which can be found at the root of the source code * + * distribution tree, or in https://www.hdfgroup.org/licenses. * + * If you do not have access to either file, you may request a copy from * + * help@hdfgroup.org. * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* NOTE! + * + * If you make any changes to H5LTanalyze.l, please run bin/genparser to + * recreate the output files. + */ + +#line 28 "hl/src//H5LTanalyze.l" +#include +#include +#include +#include + +#include "H5private.h" +#include "H5LTparse.h" + +static char *trim_quotes(const char *); +static int my_yyinput(char *, int); +#undef YY_INPUT +#define YY_INPUT(b, r, ms) (r=my_yyinput(b, ms)) +#define token(x) (int)x +#define hid(x) (hid_t)x + +#ifdef YY_BUF_SIZE +#undef YY_BUF_SIZE +#endif +#define YY_BUF_SIZE 262144 /*Define read buffer to be 256K*/ + +extern char *myinput; +extern size_t input_len; + +#line 909 "hl/src//H5LTanalyze.c" +#line 910 "hl/src//H5LTanalyze.c" + +#define INITIAL 0 + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals ( void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( void ); + +int yyget_debug ( void ); + +void yyset_debug ( int debug_flag ); + +YY_EXTRA_TYPE yyget_extra ( void ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined ); + +FILE *yyget_in ( void ); + +void yyset_in ( FILE * _in_str ); + +FILE *yyget_out ( void ); + +void yyset_out ( FILE * _out_str ); + + int yyget_leng ( void ); + +char *yyget_text ( void ); + +int yyget_lineno ( void ); + +void yyset_lineno ( int _line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( void ); +#else +extern int yywrap ( void ); +#endif +#endif + +#ifndef YY_NO_UNPUT + + static void yyunput ( int c, char *buf_ptr ); + +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * ); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput ( void ); +#else +static int input ( void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( yytext, (size_t) yyleng, 1, yyout )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + int n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = (int) fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(yyin); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (void); + +#define YY_DECL int yylex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK /*LINTED*/break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + yy_state_type yy_current_state; + char *yy_cp, *yy_bp; + int yy_act; + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_load_buffer_state( ); + } + + { +#line 53 "hl/src//H5LTanalyze.l" + + +#line 1122 "hl/src//H5LTanalyze.c" + + while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of yytext. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 275 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 300 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 55 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I8BE_TOKEN);} + YY_BREAK +case 2: +YY_RULE_SETUP +#line 56 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I8LE_TOKEN);} + YY_BREAK +case 3: +YY_RULE_SETUP +#line 57 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I16BE_TOKEN);} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 58 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I16LE_TOKEN);} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 59 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I32BE_TOKEN);} + YY_BREAK +case 6: +YY_RULE_SETUP +#line 60 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I32LE_TOKEN);} + YY_BREAK +case 7: +YY_RULE_SETUP +#line 61 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I64BE_TOKEN);} + YY_BREAK +case 8: +YY_RULE_SETUP +#line 62 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_I64LE_TOKEN);} + YY_BREAK +case 9: +YY_RULE_SETUP +#line 64 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U8BE_TOKEN);} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 65 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U8LE_TOKEN);} + YY_BREAK +case 11: +YY_RULE_SETUP +#line 66 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U16BE_TOKEN);} + YY_BREAK +case 12: +YY_RULE_SETUP +#line 67 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U16LE_TOKEN);} + YY_BREAK +case 13: +YY_RULE_SETUP +#line 68 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U32BE_TOKEN);} + YY_BREAK +case 14: +YY_RULE_SETUP +#line 69 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U32LE_TOKEN);} + YY_BREAK +case 15: +YY_RULE_SETUP +#line 70 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U64BE_TOKEN);} + YY_BREAK +case 16: +YY_RULE_SETUP +#line 71 "hl/src//H5LTanalyze.l" +{return hid(H5T_STD_U64LE_TOKEN);} + YY_BREAK +case 17: +YY_RULE_SETUP +#line 73 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_CHAR_TOKEN);} + YY_BREAK +case 18: +YY_RULE_SETUP +#line 74 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_SCHAR_TOKEN);} + YY_BREAK +case 19: +YY_RULE_SETUP +#line 75 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_UCHAR_TOKEN);} + YY_BREAK +case 20: +YY_RULE_SETUP +#line 76 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_SHORT_TOKEN);} + YY_BREAK +case 21: +YY_RULE_SETUP +#line 77 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_USHORT_TOKEN);} + YY_BREAK +case 22: +YY_RULE_SETUP +#line 78 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_INT_TOKEN);} + YY_BREAK +case 23: +YY_RULE_SETUP +#line 79 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_UINT_TOKEN);} + YY_BREAK +case 24: +YY_RULE_SETUP +#line 80 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_LONG_TOKEN);} + YY_BREAK +case 25: +YY_RULE_SETUP +#line 81 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_ULONG_TOKEN);} + YY_BREAK +case 26: +YY_RULE_SETUP +#line 82 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_LLONG_TOKEN);} + YY_BREAK +case 27: +YY_RULE_SETUP +#line 83 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_ULLONG_TOKEN);} + YY_BREAK +case 28: +YY_RULE_SETUP +#line 85 "hl/src//H5LTanalyze.l" +{return hid(H5T_IEEE_F32BE_TOKEN);} + YY_BREAK +case 29: +YY_RULE_SETUP +#line 86 "hl/src//H5LTanalyze.l" +{return hid(H5T_IEEE_F32LE_TOKEN);} + YY_BREAK +case 30: +YY_RULE_SETUP +#line 87 "hl/src//H5LTanalyze.l" +{return hid(H5T_IEEE_F64BE_TOKEN);} + YY_BREAK +case 31: +YY_RULE_SETUP +#line 88 "hl/src//H5LTanalyze.l" +{return hid(H5T_IEEE_F64LE_TOKEN);} + YY_BREAK +case 32: +YY_RULE_SETUP +#line 89 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_FLOAT_TOKEN);} + YY_BREAK +case 33: +YY_RULE_SETUP +#line 90 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_DOUBLE_TOKEN);} + YY_BREAK +case 34: +YY_RULE_SETUP +#line 91 "hl/src//H5LTanalyze.l" +{return hid(H5T_NATIVE_LDOUBLE_TOKEN);} + YY_BREAK +case 35: +YY_RULE_SETUP +#line 93 "hl/src//H5LTanalyze.l" +{return token(H5T_STRING_TOKEN);} + YY_BREAK +case 36: +YY_RULE_SETUP +#line 94 "hl/src//H5LTanalyze.l" +{return token(STRSIZE_TOKEN);} + YY_BREAK +case 37: +YY_RULE_SETUP +#line 95 "hl/src//H5LTanalyze.l" +{return token(STRPAD_TOKEN);} + YY_BREAK +case 38: +YY_RULE_SETUP +#line 96 "hl/src//H5LTanalyze.l" +{return token(CSET_TOKEN);} + YY_BREAK +case 39: +YY_RULE_SETUP +#line 97 "hl/src//H5LTanalyze.l" +{return token(CTYPE_TOKEN);} + YY_BREAK +case 40: +YY_RULE_SETUP +#line 98 "hl/src//H5LTanalyze.l" +{return token(H5T_STR_NULLTERM_TOKEN);} + YY_BREAK +case 41: +YY_RULE_SETUP +#line 99 "hl/src//H5LTanalyze.l" +{return token(H5T_STR_NULLPAD_TOKEN);} + YY_BREAK +case 42: +YY_RULE_SETUP +#line 100 "hl/src//H5LTanalyze.l" +{return token(H5T_STR_SPACEPAD_TOKEN);} + YY_BREAK +case 43: +YY_RULE_SETUP +#line 101 "hl/src//H5LTanalyze.l" +{return token(H5T_CSET_ASCII_TOKEN);} + YY_BREAK +case 44: +YY_RULE_SETUP +#line 102 "hl/src//H5LTanalyze.l" +{return token(H5T_CSET_UTF8_TOKEN);} + YY_BREAK +case 45: +YY_RULE_SETUP +#line 103 "hl/src//H5LTanalyze.l" +{return token(H5T_C_S1_TOKEN);} + YY_BREAK +case 46: +YY_RULE_SETUP +#line 104 "hl/src//H5LTanalyze.l" +{return token(H5T_FORTRAN_S1_TOKEN);} + YY_BREAK +case 47: +YY_RULE_SETUP +#line 105 "hl/src//H5LTanalyze.l" +{return token(H5T_VARIABLE_TOKEN);} + YY_BREAK +case 48: +YY_RULE_SETUP +#line 107 "hl/src//H5LTanalyze.l" +{return token(H5T_COMPOUND_TOKEN);} + YY_BREAK +case 49: +YY_RULE_SETUP +#line 108 "hl/src//H5LTanalyze.l" +{return token(H5T_ENUM_TOKEN);} + YY_BREAK +case 50: +YY_RULE_SETUP +#line 109 "hl/src//H5LTanalyze.l" +{return token(H5T_ARRAY_TOKEN);} + YY_BREAK +case 51: +YY_RULE_SETUP +#line 110 "hl/src//H5LTanalyze.l" +{return token(H5T_VLEN_TOKEN);} + YY_BREAK +case 52: +YY_RULE_SETUP +#line 112 "hl/src//H5LTanalyze.l" +{return token(H5T_OPAQUE_TOKEN);} + YY_BREAK +case 53: +YY_RULE_SETUP +#line 113 "hl/src//H5LTanalyze.l" +{return token(OPQ_SIZE_TOKEN);} + YY_BREAK +case 54: +YY_RULE_SETUP +#line 114 "hl/src//H5LTanalyze.l" +{return token(OPQ_TAG_TOKEN);} + YY_BREAK +case 55: +YY_RULE_SETUP +#line 116 "hl/src//H5LTanalyze.l" +{ + H5LTyylval.ival = atoi(yytext); + return NUMBER; + } + YY_BREAK +case 56: +/* rule 56 can match eol */ +YY_RULE_SETUP +#line 121 "hl/src//H5LTanalyze.l" +{ + H5LTyylval.sval = trim_quotes(yytext); + return STRING; + } + YY_BREAK +case 57: +YY_RULE_SETUP +#line 126 "hl/src//H5LTanalyze.l" +{return token('{');} + YY_BREAK +case 58: +YY_RULE_SETUP +#line 127 "hl/src//H5LTanalyze.l" +{return token('}');} + YY_BREAK +case 59: +YY_RULE_SETUP +#line 128 "hl/src//H5LTanalyze.l" +{return token('[');} + YY_BREAK +case 60: +YY_RULE_SETUP +#line 129 "hl/src//H5LTanalyze.l" +{return token(']');} + YY_BREAK +case 61: +YY_RULE_SETUP +#line 130 "hl/src//H5LTanalyze.l" +{return token(':');} + YY_BREAK +case 62: +YY_RULE_SETUP +#line 131 "hl/src//H5LTanalyze.l" +{return token(';');} + YY_BREAK +case 63: +/* rule 63 can match eol */ +YY_RULE_SETUP +#line 132 "hl/src//H5LTanalyze.l" +; + YY_BREAK +case 64: +YY_RULE_SETUP +#line 134 "hl/src//H5LTanalyze.l" +ECHO; + YY_BREAK +#line 1507 "hl/src//H5LTanalyze.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_c_buf_p); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( yywrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of user's declarations */ +} /* end of yylex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + char *source = (yytext_ptr); + int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr) - 1); + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yyrealloc( (void *) b->yy_ch_buf, + (yy_size_t) (b->yy_buf_size + 2) ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = NULL; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if (((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc( + (void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf, (yy_size_t) new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + /* "- 2" to take care of EOB's */ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size = (int) (new_size - 2); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + yy_state_type yy_current_state; + char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 275 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + int yy_is_jam; + char *yy_cp = (yy_c_buf_p); + + YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 275 ) + yy_c = yy_meta[yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; + yy_is_jam = (yy_current_state == 274); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_UNPUT + + static void yyunput (int c, char * yy_bp ) +{ + char *yy_cp; + + yy_cp = (yy_c_buf_p); + + /* undo effects of setting up yytext */ + *yy_cp = (yy_hold_char); + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + int number_to_move = (yy_n_chars) + 2; + char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; + char *source = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; + + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = (int) YY_CURRENT_BUFFER_LVALUE->yy_buf_size; + + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} + +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (int) ((yy_c_buf_p) - (yytext_ptr)); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap( ) ) + return 0; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve yytext */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void yyrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + yyensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + yy_create_buffer( yyin, YY_BUF_SIZE ); + } + + yy_init_buffer( YY_CURRENT_BUFFER, input_file ); + yy_load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * yypop_buffer_state(); + * yypush_buffer_state(new_buffer); + */ + yyensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + yy_load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void yy_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yyalloc( (yy_size_t) (b->yy_buf_size + 2) ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with yy_create_buffer() + * + */ + void yy_delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yyfree( (void *) b->yy_ch_buf ); + + yyfree( (void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a yyrestart() or at EOF. + */ + static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then yy_init_buffer was _probably_ + * called from yyrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void yy_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + yy_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + yyensure_buffer_stack(); + + /* This block is copied from yy_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from yy_switch_to_buffer. */ + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void yypop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + yy_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + yy_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void yyensure_buffer_stack (void) +{ + yy_size_t num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ + (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + yy_size_t grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return NULL; + + b = (YY_BUFFER_STATE) yyalloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = (int) (size - 2); /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = NULL; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to yylex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * yy_scan_bytes() instead. + */ +YY_BUFFER_STATE yy_scan_string (const char * yystr ) +{ + + return yy_scan_bytes( yystr, (int) strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to yylex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE yy_scan_bytes (const char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = (yy_size_t) (_yybytes_len + 2); + buf = (char *) yyalloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yynoreturn yy_fatal_error (const char* msg ) +{ + fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + yytext[yyleng] = (yy_hold_char); \ + (yy_c_buf_p) = yytext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + yyleng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int yyget_lineno (void) +{ + + return yylineno; +} + +/** Get the input stream. + * + */ +FILE *yyget_in (void) +{ + return yyin; +} + +/** Get the output stream. + * + */ +FILE *yyget_out (void) +{ + return yyout; +} + +/** Get the length of the current token. + * + */ +int yyget_leng (void) +{ + return yyleng; +} + +/** Get the current token. + * + */ + +char *yyget_text (void) +{ + return yytext; +} + +/** Set the current line number. + * @param _line_number line number + * + */ +void yyset_lineno (int _line_number ) +{ + + yylineno = _line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param _in_str A readable stream. + * + * @see yy_switch_to_buffer + */ +void yyset_in (FILE * _in_str ) +{ + yyin = _in_str ; +} + +void yyset_out (FILE * _out_str ) +{ + yyout = _out_str ; +} + +int yyget_debug (void) +{ + return yy_flex_debug; +} + +void yyset_debug (int _bdebug ) +{ + yy_flex_debug = _bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from yylex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = NULL; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = NULL; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + yyin = stdin; + yyout = stdout; +#else + yyin = NULL; + yyout = NULL; +#endif + + /* For future reference: Set errno on error, since we are called by + * yylex_init() + */ + return 0; +} + +/* yylex_destroy is for both reentrant and non-reentrant scanners. */ +int yylex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + yy_delete_buffer( YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + yypop_buffer_state(); + } + + /* Destroy the stack itself. */ + yyfree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * yylex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, const char * s2, int n ) +{ + + int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (const char * s ) +{ + int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *yyalloc (yy_size_t size ) +{ + return malloc(size); +} + +void *yyrealloc (void * ptr, yy_size_t size ) +{ + + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return realloc(ptr, size); +} + +void yyfree (void * ptr ) +{ + free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 134 "hl/src//H5LTanalyze.l" + + +/* Allocate a copy of `quoted` with the double quote character at + * the beginning and the one at the end both removed. The caller is + * responsible for free()ing the copy. + */ +static char * +trim_quotes(const char *quoted) +{ + size_t len = strlen(quoted); + char *trimmed; + + assert(quoted[0] == '"' && quoted[len - 1] == '"'); + + trimmed = strdup(quoted + 1); + trimmed[len - 2] = '\0'; + + return trimmed; +} + +static int my_yyinput(char *buf, int max_size) +{ + int ret; + + memcpy(buf, myinput, input_len); + ret = (int)input_len; + return ret; +} + +int H5LTyyerror(const char *msg) +{ + printf("ERROR: %s before \"%s\".\n", msg, yytext); + return 0; +} + +int yywrap() +{ + return 1; +} + diff --git a/modules/drivers/hdf5/source/H5LTparse.c b/modules/drivers/hdf5/source/H5LTparse.c new file mode 100644 index 000000000..592b86320 --- /dev/null +++ b/modules/drivers/hdf5/source/H5LTparse.c @@ -0,0 +1,2121 @@ +#if defined (__GNUC__) +#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402 +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wimplicit-function-declaration" +#pragma GCC diagnostic ignored "-Wmissing-prototypes" +#pragma GCC diagnostic ignored "-Wnested-externs" +#pragma GCC diagnostic ignored "-Wold-style-definition" +#pragma GCC diagnostic ignored "-Wredundant-decls" +#pragma GCC diagnostic ignored "-Wsign-compare" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wstrict-overflow" +#pragma GCC diagnostic ignored "-Wstrict-prototypes" +#pragma GCC diagnostic ignored "-Wimplicit-fallthrough" +#if !defined (__clang__) +#pragma GCC diagnostic ignored "-Wlarger-than=" +#pragma GCC diagnostic ignored "-Wsuggest-attribute=const" +#pragma GCC diagnostic ignored "-Wsuggest-attribute=pure" +#endif +#pragma GCC diagnostic ignored "-Wswitch-default" +#pragma GCC diagnostic ignored "-Wunused-function" +#pragma GCC diagnostic ignored "-Wunused-macros" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif +#if ((__GNUC__ * 100) + __GNUC_MINOR__) >= 600 +#pragma GCC diagnostic ignored "-Wnull-dereference" +#endif +#elif defined __SUNPRO_CC +#pragma disable_warn +#elif defined _MSC_VER +#pragma warning(push, 1) +#endif +/* A Bison parser, made by GNU Bison 3.8.2. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, + Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual, + especially those whose name start with YY_ or yy_. They are + private implementation details that can be changed or removed. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output, and Bison version. */ +#define YYBISON 30802 + +/* Bison version string. */ +#define YYBISON_VERSION "3.8.2" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse H5LTyyparse +#define yylex H5LTyylex +#define yyerror H5LTyyerror +#define yydebug H5LTyydebug +#define yynerrs H5LTyynerrs +#define yylval H5LTyylval +#define yychar H5LTyychar + +/* First part of user prologue. */ +#line 19 "hl/src//H5LTparse.y" + +#include +#include +#include + +#include "H5private.h" + +extern int yylex(void); +extern int yyerror(const char *); + +#define STACK_SIZE 16 + +/*structure for compound type information*/ +struct cmpd_info { + hid_t id; /*type ID*/ + bool is_field; /*flag to lexer for compound member*/ + bool first_memb; /*flag for first compound member*/ +}; + +/*stack for nested compound type*/ +static struct cmpd_info cmpd_stack[STACK_SIZE] = { + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, + {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1} }; + +static int csindex = -1; /*pointer to the top of compound stack*/ + +/*structure for array type information*/ +struct arr_info { + hsize_t dims[H5S_MAX_RANK]; /*size of each dimension, limited to 32 dimensions*/ + unsigned ndims; /*number of dimensions*/ + bool is_dim; /*flag to lexer for dimension*/ +}; +/*stack for nested array type*/ +static struct arr_info arr_stack[STACK_SIZE]; +static int asindex = -1; /*pointer to the top of array stack*/ + +static H5T_str_t str_pad; /*variable for string padding*/ +static H5T_cset_t str_cset; /*variable for string character set*/ +static bool is_variable = 0; /*variable for variable-length string*/ +static size_t str_size; /*variable for string size*/ + +static hid_t enum_id; /*type ID*/ +static bool is_enum = 0; /*flag to lexer for enum type*/ +static bool is_enum_memb = 0; /*flag to lexer for enum member*/ +static char* enum_memb_symbol; /*enum member symbol string*/ + + +#line 128 "hl/src//H5LTparse.c" + +# ifndef YY_CAST +# ifdef __cplusplus +# define YY_CAST(Type, Val) static_cast (Val) +# define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast (Val) +# else +# define YY_CAST(Type, Val) ((Type) (Val)) +# define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val)) +# endif +# endif +# ifndef YY_NULLPTR +# if defined __cplusplus +# if 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# else +# define YY_NULLPTR ((void*)0) +# endif +# endif + +#include "H5LTparse.h" +/* Symbol kind. */ +enum yysymbol_kind_t +{ + YYSYMBOL_YYEMPTY = -2, + YYSYMBOL_YYEOF = 0, /* "end of file" */ + YYSYMBOL_YYerror = 1, /* error */ + YYSYMBOL_YYUNDEF = 2, /* "invalid token" */ + YYSYMBOL_H5T_STD_I8BE_TOKEN = 3, /* H5T_STD_I8BE_TOKEN */ + YYSYMBOL_H5T_STD_I8LE_TOKEN = 4, /* H5T_STD_I8LE_TOKEN */ + YYSYMBOL_H5T_STD_I16BE_TOKEN = 5, /* H5T_STD_I16BE_TOKEN */ + YYSYMBOL_H5T_STD_I16LE_TOKEN = 6, /* H5T_STD_I16LE_TOKEN */ + YYSYMBOL_H5T_STD_I32BE_TOKEN = 7, /* H5T_STD_I32BE_TOKEN */ + YYSYMBOL_H5T_STD_I32LE_TOKEN = 8, /* H5T_STD_I32LE_TOKEN */ + YYSYMBOL_H5T_STD_I64BE_TOKEN = 9, /* H5T_STD_I64BE_TOKEN */ + YYSYMBOL_H5T_STD_I64LE_TOKEN = 10, /* H5T_STD_I64LE_TOKEN */ + YYSYMBOL_H5T_STD_U8BE_TOKEN = 11, /* H5T_STD_U8BE_TOKEN */ + YYSYMBOL_H5T_STD_U8LE_TOKEN = 12, /* H5T_STD_U8LE_TOKEN */ + YYSYMBOL_H5T_STD_U16BE_TOKEN = 13, /* H5T_STD_U16BE_TOKEN */ + YYSYMBOL_H5T_STD_U16LE_TOKEN = 14, /* H5T_STD_U16LE_TOKEN */ + YYSYMBOL_H5T_STD_U32BE_TOKEN = 15, /* H5T_STD_U32BE_TOKEN */ + YYSYMBOL_H5T_STD_U32LE_TOKEN = 16, /* H5T_STD_U32LE_TOKEN */ + YYSYMBOL_H5T_STD_U64BE_TOKEN = 17, /* H5T_STD_U64BE_TOKEN */ + YYSYMBOL_H5T_STD_U64LE_TOKEN = 18, /* H5T_STD_U64LE_TOKEN */ + YYSYMBOL_H5T_NATIVE_CHAR_TOKEN = 19, /* H5T_NATIVE_CHAR_TOKEN */ + YYSYMBOL_H5T_NATIVE_SCHAR_TOKEN = 20, /* H5T_NATIVE_SCHAR_TOKEN */ + YYSYMBOL_H5T_NATIVE_UCHAR_TOKEN = 21, /* H5T_NATIVE_UCHAR_TOKEN */ + YYSYMBOL_H5T_NATIVE_SHORT_TOKEN = 22, /* H5T_NATIVE_SHORT_TOKEN */ + YYSYMBOL_H5T_NATIVE_USHORT_TOKEN = 23, /* H5T_NATIVE_USHORT_TOKEN */ + YYSYMBOL_H5T_NATIVE_INT_TOKEN = 24, /* H5T_NATIVE_INT_TOKEN */ + YYSYMBOL_H5T_NATIVE_UINT_TOKEN = 25, /* H5T_NATIVE_UINT_TOKEN */ + YYSYMBOL_H5T_NATIVE_LONG_TOKEN = 26, /* H5T_NATIVE_LONG_TOKEN */ + YYSYMBOL_H5T_NATIVE_ULONG_TOKEN = 27, /* H5T_NATIVE_ULONG_TOKEN */ + YYSYMBOL_H5T_NATIVE_LLONG_TOKEN = 28, /* H5T_NATIVE_LLONG_TOKEN */ + YYSYMBOL_H5T_NATIVE_ULLONG_TOKEN = 29, /* H5T_NATIVE_ULLONG_TOKEN */ + YYSYMBOL_H5T_IEEE_F32BE_TOKEN = 30, /* H5T_IEEE_F32BE_TOKEN */ + YYSYMBOL_H5T_IEEE_F32LE_TOKEN = 31, /* H5T_IEEE_F32LE_TOKEN */ + YYSYMBOL_H5T_IEEE_F64BE_TOKEN = 32, /* H5T_IEEE_F64BE_TOKEN */ + YYSYMBOL_H5T_IEEE_F64LE_TOKEN = 33, /* H5T_IEEE_F64LE_TOKEN */ + YYSYMBOL_H5T_NATIVE_FLOAT_TOKEN = 34, /* H5T_NATIVE_FLOAT_TOKEN */ + YYSYMBOL_H5T_NATIVE_DOUBLE_TOKEN = 35, /* H5T_NATIVE_DOUBLE_TOKEN */ + YYSYMBOL_H5T_NATIVE_LDOUBLE_TOKEN = 36, /* H5T_NATIVE_LDOUBLE_TOKEN */ + YYSYMBOL_H5T_STRING_TOKEN = 37, /* H5T_STRING_TOKEN */ + YYSYMBOL_STRSIZE_TOKEN = 38, /* STRSIZE_TOKEN */ + YYSYMBOL_STRPAD_TOKEN = 39, /* STRPAD_TOKEN */ + YYSYMBOL_CSET_TOKEN = 40, /* CSET_TOKEN */ + YYSYMBOL_CTYPE_TOKEN = 41, /* CTYPE_TOKEN */ + YYSYMBOL_H5T_VARIABLE_TOKEN = 42, /* H5T_VARIABLE_TOKEN */ + YYSYMBOL_H5T_STR_NULLTERM_TOKEN = 43, /* H5T_STR_NULLTERM_TOKEN */ + YYSYMBOL_H5T_STR_NULLPAD_TOKEN = 44, /* H5T_STR_NULLPAD_TOKEN */ + YYSYMBOL_H5T_STR_SPACEPAD_TOKEN = 45, /* H5T_STR_SPACEPAD_TOKEN */ + YYSYMBOL_H5T_CSET_ASCII_TOKEN = 46, /* H5T_CSET_ASCII_TOKEN */ + YYSYMBOL_H5T_CSET_UTF8_TOKEN = 47, /* H5T_CSET_UTF8_TOKEN */ + YYSYMBOL_H5T_C_S1_TOKEN = 48, /* H5T_C_S1_TOKEN */ + YYSYMBOL_H5T_FORTRAN_S1_TOKEN = 49, /* H5T_FORTRAN_S1_TOKEN */ + YYSYMBOL_H5T_OPAQUE_TOKEN = 50, /* H5T_OPAQUE_TOKEN */ + YYSYMBOL_OPQ_SIZE_TOKEN = 51, /* OPQ_SIZE_TOKEN */ + YYSYMBOL_OPQ_TAG_TOKEN = 52, /* OPQ_TAG_TOKEN */ + YYSYMBOL_H5T_COMPOUND_TOKEN = 53, /* H5T_COMPOUND_TOKEN */ + YYSYMBOL_H5T_ENUM_TOKEN = 54, /* H5T_ENUM_TOKEN */ + YYSYMBOL_H5T_ARRAY_TOKEN = 55, /* H5T_ARRAY_TOKEN */ + YYSYMBOL_H5T_VLEN_TOKEN = 56, /* H5T_VLEN_TOKEN */ + YYSYMBOL_STRING = 57, /* STRING */ + YYSYMBOL_NUMBER = 58, /* NUMBER */ + YYSYMBOL_59_ = 59, /* '{' */ + YYSYMBOL_60_ = 60, /* '}' */ + YYSYMBOL_61_ = 61, /* '[' */ + YYSYMBOL_62_ = 62, /* ']' */ + YYSYMBOL_63_ = 63, /* ':' */ + YYSYMBOL_64_ = 64, /* ';' */ + YYSYMBOL_YYACCEPT = 65, /* $accept */ + YYSYMBOL_start = 66, /* start */ + YYSYMBOL_ddl_type = 67, /* ddl_type */ + YYSYMBOL_atomic_type = 68, /* atomic_type */ + YYSYMBOL_integer_type = 69, /* integer_type */ + YYSYMBOL_fp_type = 70, /* fp_type */ + YYSYMBOL_compound_type = 71, /* compound_type */ + YYSYMBOL_72_1 = 72, /* $@1 */ + YYSYMBOL_memb_list = 73, /* memb_list */ + YYSYMBOL_memb_def = 74, /* memb_def */ + YYSYMBOL_75_2 = 75, /* $@2 */ + YYSYMBOL_field_name = 76, /* field_name */ + YYSYMBOL_field_offset = 77, /* field_offset */ + YYSYMBOL_offset = 78, /* offset */ + YYSYMBOL_array_type = 79, /* array_type */ + YYSYMBOL_80_3 = 80, /* $@3 */ + YYSYMBOL_dim_list = 81, /* dim_list */ + YYSYMBOL_dim = 82, /* dim */ + YYSYMBOL_83_4 = 83, /* $@4 */ + YYSYMBOL_84_5 = 84, /* $@5 */ + YYSYMBOL_dimsize = 85, /* dimsize */ + YYSYMBOL_vlen_type = 86, /* vlen_type */ + YYSYMBOL_opaque_type = 87, /* opaque_type */ + YYSYMBOL_88_6 = 88, /* @6 */ + YYSYMBOL_89_7 = 89, /* $@7 */ + YYSYMBOL_opaque_size = 90, /* opaque_size */ + YYSYMBOL_opaque_tag = 91, /* opaque_tag */ + YYSYMBOL_string_type = 92, /* string_type */ + YYSYMBOL_93_8 = 93, /* $@8 */ + YYSYMBOL_94_9 = 94, /* $@9 */ + YYSYMBOL_95_10 = 95, /* $@10 */ + YYSYMBOL_96_11 = 96, /* @11 */ + YYSYMBOL_strsize = 97, /* strsize */ + YYSYMBOL_strpad = 98, /* strpad */ + YYSYMBOL_cset = 99, /* cset */ + YYSYMBOL_ctype = 100, /* ctype */ + YYSYMBOL_enum_type = 101, /* enum_type */ + YYSYMBOL_102_12 = 102, /* $@12 */ + YYSYMBOL_enum_list = 103, /* enum_list */ + YYSYMBOL_enum_def = 104, /* enum_def */ + YYSYMBOL_105_13 = 105, /* $@13 */ + YYSYMBOL_enum_symbol = 106, /* enum_symbol */ + YYSYMBOL_enum_val = 107 /* enum_val */ +}; +typedef enum yysymbol_kind_t yysymbol_kind_t; + + + + +#ifdef short +# undef short +#endif + +/* On compilers that do not define __PTRDIFF_MAX__ etc., make sure + and (if available) are included + so that the code can choose integer types of a good width. */ + +#ifndef __PTRDIFF_MAX__ +# include /* INFRINGES ON USER NAME SPACE */ +# if defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_STDINT_H +# endif +#endif + +/* Narrow types that promote to a signed type and that can represent a + signed or unsigned integer of at least N bits. In tables they can + save space and decrease cache pressure. Promoting to a signed type + helps avoid bugs in integer arithmetic. */ + +#ifdef __INT_LEAST8_MAX__ +typedef __INT_LEAST8_TYPE__ yytype_int8; +#elif defined YY_STDINT_H +typedef int_least8_t yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef __INT_LEAST16_MAX__ +typedef __INT_LEAST16_TYPE__ yytype_int16; +#elif defined YY_STDINT_H +typedef int_least16_t yytype_int16; +#else +typedef short yytype_int16; +#endif + +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + . */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + +#if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST8_TYPE__ yytype_uint8; +#elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST8_MAX <= INT_MAX) +typedef uint_least8_t yytype_uint8; +#elif !defined __UINT_LEAST8_MAX__ && UCHAR_MAX <= INT_MAX +typedef unsigned char yytype_uint8; +#else +typedef short yytype_uint8; +#endif + +#if defined __UINT_LEAST16_MAX__ && __UINT_LEAST16_MAX__ <= __INT_MAX__ +typedef __UINT_LEAST16_TYPE__ yytype_uint16; +#elif (!defined __UINT_LEAST16_MAX__ && defined YY_STDINT_H \ + && UINT_LEAST16_MAX <= INT_MAX) +typedef uint_least16_t yytype_uint16; +#elif !defined __UINT_LEAST16_MAX__ && USHRT_MAX <= INT_MAX +typedef unsigned short yytype_uint16; +#else +typedef int yytype_uint16; +#endif + +#ifndef YYPTRDIFF_T +# if defined __PTRDIFF_TYPE__ && defined __PTRDIFF_MAX__ +# define YYPTRDIFF_T __PTRDIFF_TYPE__ +# define YYPTRDIFF_MAXIMUM __PTRDIFF_MAX__ +# elif defined PTRDIFF_MAX +# ifndef ptrdiff_t +# include /* INFRINGES ON USER NAME SPACE */ +# endif +# define YYPTRDIFF_T ptrdiff_t +# define YYPTRDIFF_MAXIMUM PTRDIFF_MAX +# else +# define YYPTRDIFF_T long +# define YYPTRDIFF_MAXIMUM LONG_MAX +# endif +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif defined __STDC_VERSION__ && 199901 <= __STDC_VERSION__ +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned +# endif +#endif + +#define YYSIZE_MAXIMUM \ + YY_CAST (YYPTRDIFF_T, \ + (YYPTRDIFF_MAXIMUM < YY_CAST (YYSIZE_T, -1) \ + ? YYPTRDIFF_MAXIMUM \ + : YY_CAST (YYSIZE_T, -1))) + +#define YYSIZEOF(X) YY_CAST (YYPTRDIFF_T, sizeof (X)) + + +/* Stored state numbers (used for stacks). */ +typedef yytype_uint8 yy_state_t; + +/* State numbers in computations. */ +typedef int yy_state_fast_t; + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + + +#ifndef YY_ATTRIBUTE_PURE +# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_PURE __attribute__ ((__pure__)) +# else +# define YY_ATTRIBUTE_PURE +# endif +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__) +# define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__)) +# else +# define YY_ATTRIBUTE_UNUSED +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YY_USE(E) ((void) (E)) +#else +# define YY_USE(E) /* empty */ +#endif + +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + +#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__ +# define YY_IGNORE_USELESS_CAST_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"") +# define YY_IGNORE_USELESS_CAST_END \ + _Pragma ("GCC diagnostic pop") +#endif +#ifndef YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_BEGIN +# define YY_IGNORE_USELESS_CAST_END +#endif + + +#define YY_ASSERT(E) ((void) (0 && (E))) + +#if !defined yyoverflow + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* !defined yyoverflow */ + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yy_state_t yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (YYSIZEOF (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (YYSIZEOF (yy_state_t) + YYSIZEOF (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYPTRDIFF_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * YYSIZEOF (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / YYSIZEOF (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, YY_CAST (YYSIZE_T, (Count)) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYPTRDIFF_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 58 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 197 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 65 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 43 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 92 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 134 + +/* YYMAXUTOK -- Last valid token kind. */ +#define YYMAXUTOK 313 + + +/* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, with out-of-bounds checking. */ +#define YYTRANSLATE(YYX) \ + (0 <= (YYX) && (YYX) <= YYMAXUTOK \ + ? YY_CAST (yysymbol_kind_t, yytranslate[YYX]) \ + : YYSYMBOL_YYUNDEF) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex. */ +static const yytype_int8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 63, 64, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 61, 2, 62, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 59, 2, 60, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58 +}; + +#if YYDEBUG +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_int16 yyrline[] = +{ + 0, 101, 101, 102, 104, 105, 106, 107, 109, 110, + 111, 112, 113, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 145, 146, 147, 148, 149, 150, 151, 155, 154, 163, + 164, 166, 166, 203, 211, 212, 215, 217, 217, 226, + 227, 229, 230, 229, 237, 240, 247, 252, 244, 259, + 261, 266, 273, 282, 289, 263, 313, 314, 316, 317, + 318, 320, 321, 323, 324, 328, 327, 332, 333, 335, + 335, 385, 387 +}; +#endif + +/** Accessing symbol of state STATE. */ +#define YY_ACCESSING_SYMBOL(State) YY_CAST (yysymbol_kind_t, yystos[State]) + +#if YYDEBUG || 0 +/* The user-facing name of the symbol whose (internal) number is + YYSYMBOL. No bounds checking. */ +static const char *yysymbol_name (yysymbol_kind_t yysymbol) YY_ATTRIBUTE_UNUSED; + +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "\"end of file\"", "error", "\"invalid token\"", "H5T_STD_I8BE_TOKEN", + "H5T_STD_I8LE_TOKEN", "H5T_STD_I16BE_TOKEN", "H5T_STD_I16LE_TOKEN", + "H5T_STD_I32BE_TOKEN", "H5T_STD_I32LE_TOKEN", "H5T_STD_I64BE_TOKEN", + "H5T_STD_I64LE_TOKEN", "H5T_STD_U8BE_TOKEN", "H5T_STD_U8LE_TOKEN", + "H5T_STD_U16BE_TOKEN", "H5T_STD_U16LE_TOKEN", "H5T_STD_U32BE_TOKEN", + "H5T_STD_U32LE_TOKEN", "H5T_STD_U64BE_TOKEN", "H5T_STD_U64LE_TOKEN", + "H5T_NATIVE_CHAR_TOKEN", "H5T_NATIVE_SCHAR_TOKEN", + "H5T_NATIVE_UCHAR_TOKEN", "H5T_NATIVE_SHORT_TOKEN", + "H5T_NATIVE_USHORT_TOKEN", "H5T_NATIVE_INT_TOKEN", + "H5T_NATIVE_UINT_TOKEN", "H5T_NATIVE_LONG_TOKEN", + "H5T_NATIVE_ULONG_TOKEN", "H5T_NATIVE_LLONG_TOKEN", + "H5T_NATIVE_ULLONG_TOKEN", "H5T_IEEE_F32BE_TOKEN", + "H5T_IEEE_F32LE_TOKEN", "H5T_IEEE_F64BE_TOKEN", "H5T_IEEE_F64LE_TOKEN", + "H5T_NATIVE_FLOAT_TOKEN", "H5T_NATIVE_DOUBLE_TOKEN", + "H5T_NATIVE_LDOUBLE_TOKEN", "H5T_STRING_TOKEN", "STRSIZE_TOKEN", + "STRPAD_TOKEN", "CSET_TOKEN", "CTYPE_TOKEN", "H5T_VARIABLE_TOKEN", + "H5T_STR_NULLTERM_TOKEN", "H5T_STR_NULLPAD_TOKEN", + "H5T_STR_SPACEPAD_TOKEN", "H5T_CSET_ASCII_TOKEN", "H5T_CSET_UTF8_TOKEN", + "H5T_C_S1_TOKEN", "H5T_FORTRAN_S1_TOKEN", "H5T_OPAQUE_TOKEN", + "OPQ_SIZE_TOKEN", "OPQ_TAG_TOKEN", "H5T_COMPOUND_TOKEN", + "H5T_ENUM_TOKEN", "H5T_ARRAY_TOKEN", "H5T_VLEN_TOKEN", "STRING", + "NUMBER", "'{'", "'}'", "'['", "']'", "':'", "';'", "$accept", "start", + "ddl_type", "atomic_type", "integer_type", "fp_type", "compound_type", + "$@1", "memb_list", "memb_def", "$@2", "field_name", "field_offset", + "offset", "array_type", "$@3", "dim_list", "dim", "$@4", "$@5", + "dimsize", "vlen_type", "opaque_type", "@6", "$@7", "opaque_size", + "opaque_tag", "string_type", "$@8", "$@9", "$@10", "@11", "strsize", + "strpad", "cset", "ctype", "enum_type", "$@12", "enum_list", "enum_def", + "$@13", "enum_symbol", "enum_val", YY_NULLPTR +}; + +static const char * +yysymbol_name (yysymbol_kind_t yysymbol) +{ + return yytname[yysymbol]; +} +#endif + +#define YYPACT_NINF (-25) + +#define yypact_value_is_default(Yyn) \ + ((Yyn) == YYPACT_NINF) + +#define YYTABLE_NINF (-1) + +#define yytable_value_is_error(Yyn) \ + 0 + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int16 yypact[] = +{ + 114, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -24, -22, -25, -13, -25, + -11, 49, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, 18, 45, 38, 168, 39, 114, -25, -4, + 41, -25, 36, -25, 42, -25, -25, 37, -25, 40, + 56, -25, -3, -25, -25, -25, -25, -25, -25, -25, + -25, 43, -25, 66, 55, 51, -21, 57, -25, 0, + 95, -25, 50, -25, -25, -25, -25, -25, -25, -25, + -25, -25, 89, -25, 90, 97, 92, 99, 52, -25, + -25, -25, -25, -25, -25, 94, -25, 119, 100, -25, + -6, -25, -25, -25, 98, -25, 120, 46, -25, -25, + 101, -25, 103, -25 +}; + +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_int8 yydefact[] = +{ + 2, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 0, 0, 47, 0, 57, + 0, 0, 3, 4, 8, 9, 5, 6, 7, 12, + 10, 11, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 49, 0, 59, 0, 76, 77, 0, 69, 0, + 0, 85, 0, 65, 71, 66, 48, 51, 50, 87, + 61, 0, 60, 0, 0, 0, 0, 0, 58, 0, + 0, 53, 54, 91, 86, 88, 89, 64, 62, 78, + 79, 80, 0, 70, 0, 0, 0, 0, 0, 72, + 67, 56, 55, 52, 92, 0, 63, 0, 0, 90, + 0, 68, 81, 82, 0, 73, 0, 0, 83, 84, + 0, 74, 0, 75 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -25, -25, -15, -25, 111, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25, -25, -25, -25, -25, -25, -25, -25, + -25, -25, -25 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_uint8 yydefgoto[] = +{ + 0, 41, 42, 43, 44, 45, 46, 54, 70, 78, + 85, 92, 106, 112, 47, 56, 72, 82, 87, 108, + 98, 48, 49, 84, 118, 69, 104, 50, 83, 117, + 126, 132, 67, 102, 124, 130, 51, 79, 86, 95, + 107, 96, 115 +}; + +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 52, 93, 53, 65, 94, + 122, 123, 64, 99, 100, 101, 55, 36, 57, 58, + 37, 38, 39, 40, 66, 77, 59, 81, 80, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 128, 129, 60, 61, 63, 68, + 71, 74, 73, 88, 75, 89, 36, 90, 91, 37, + 38, 39, 40, 105, 116, 97, 76, 1, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 103, 109, 110, 111, 113, 114, 119, 120, + 121, 127, 125, 133, 36, 131, 62, 37, 38, 39, + 40, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27 +}; + +static const yytype_int8 yycheck[] = +{ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 59, 57, 59, 42, 60, + 46, 47, 57, 43, 44, 45, 59, 50, 59, 0, + 53, 54, 55, 56, 58, 70, 38, 72, 61, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 48, 49, 51, 59, 59, 58, + 64, 64, 60, 60, 64, 39, 50, 52, 57, 53, + 54, 55, 56, 63, 62, 58, 60, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 57, 64, 64, 58, 64, 58, 64, 40, + 60, 41, 64, 60, 50, 64, 55, 53, 54, 55, + 56, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29 +}; + +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ +static const yytype_int8 yystos[] = +{ + 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 50, 53, 54, 55, + 56, 66, 67, 68, 69, 70, 71, 79, 86, 87, + 92, 101, 59, 59, 72, 59, 80, 59, 0, 38, + 51, 59, 69, 59, 67, 42, 58, 97, 58, 90, + 73, 64, 81, 60, 64, 64, 60, 67, 74, 102, + 61, 67, 82, 93, 88, 75, 103, 83, 60, 39, + 52, 57, 76, 57, 60, 104, 106, 58, 85, 43, + 44, 45, 98, 57, 91, 63, 77, 105, 84, 64, + 64, 58, 78, 64, 58, 107, 62, 94, 89, 64, + 40, 60, 46, 47, 99, 64, 95, 41, 48, 49, + 100, 64, 96, 60 +}; + +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr1[] = +{ + 0, 65, 66, 66, 67, 67, 67, 67, 68, 68, + 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 70, 70, 70, 70, 70, 70, 70, 72, 71, 73, + 73, 75, 74, 76, 77, 77, 78, 80, 79, 81, + 81, 83, 84, 82, 85, 86, 88, 89, 87, 90, + 91, 93, 94, 95, 96, 92, 97, 97, 98, 98, + 98, 99, 99, 100, 100, 102, 101, 103, 103, 105, + 104, 106, 107 +}; + +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ +static const yytype_int8 yyr2[] = +{ + 0, 2, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 5, 0, + 2, 0, 5, 1, 0, 2, 1, 0, 6, 0, + 2, 0, 0, 5, 1, 4, 0, 0, 11, 1, + 1, 0, 0, 0, 0, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 7, 0, 2, 0, + 4, 1, 1 +}; + + +enum { YYENOMEM = -2 }; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ + do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ + while (0) + +/* Backward compatibility with an undocumented macro. + Use YYerror or YYUNDEF. */ +#define YYERRCODE YYUNDEF + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + + + +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Kind, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*-----------------------------------. +| Print this symbol's value on YYO. | +`-----------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) +{ + FILE *yyoutput = yyo; + YY_USE (yyoutput); + if (!yyvaluep) + return; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/*---------------------------. +| Print this symbol on YYO. | +`---------------------------*/ + +static void +yy_symbol_print (FILE *yyo, + yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep) +{ + YYFPRINTF (yyo, "%s %s (", + yykind < YYNTOKENS ? "token" : "nterm", yysymbol_name (yykind)); + + yy_symbol_value_print (yyo, yykind, yyvaluep); + YYFPRINTF (yyo, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yy_state_t *yybottom, yy_state_t *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yy_state_t *yyssp, YYSTYPE *yyvsp, + int yyrule) +{ + int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %d):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + YY_ACCESSING_SYMBOL (+yyssp[yyi + 1 - yynrhs]), + &yyvsp[(yyi + 1) - (yynrhs)]); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, Rule); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) ((void) 0) +# define YY_SYMBOL_PRINT(Title, Kind, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + + + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, + yysymbol_kind_t yykind, YYSTYPE *yyvaluep) +{ + YY_USE (yyvaluep); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YY_USE (yykind); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + +/* Lookahead token kind. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; +/* Number of syntax errors so far. */ +int yynerrs; + + + + +/*----------. +| yyparse. | +`----------*/ + +hid_t +yyparse (void) +{ + yy_state_fast_t yystate = 0; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus = 0; + + /* Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* Their size. */ + YYPTRDIFF_T yystacksize = YYINITDEPTH; + + /* The state stack: array, bottom, top. */ + yy_state_t yyssa[YYINITDEPTH]; + yy_state_t *yyss = yyssa; + yy_state_t *yyssp = yyss; + + /* The semantic value stack: array, bottom, top. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp = yyvs; + + int yyn; + /* The return value of yyparse. */ + int yyresult; + /* Lookahead symbol kind. */ + yysymbol_kind_t yytoken = YYSYMBOL_YYEMPTY; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yychar = YYEMPTY; /* Cause a token to be read. */ + + goto yysetstate; + + +/*------------------------------------------------------------. +| yynewstate -- push a new state, which is found in yystate. | +`------------------------------------------------------------*/ +yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + +/*--------------------------------------------------------------------. +| yysetstate -- set current state (the top of the stack) to yystate. | +`--------------------------------------------------------------------*/ +yysetstate: + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + YY_ASSERT (0 <= yystate && yystate < YYNSTATES); + YY_IGNORE_USELESS_CAST_BEGIN + *yyssp = YY_CAST (yy_state_t, yystate); + YY_IGNORE_USELESS_CAST_END + YY_STACK_PRINT (yyss, yyssp); + + if (yyss + yystacksize - 1 <= yyssp) +#if !defined yyoverflow && !defined YYSTACK_RELOCATE + YYNOMEM; +#else + { + /* Get the current used size of the three stacks, in elements. */ + YYPTRDIFF_T yysize = yyssp - yyss + 1; + +# if defined yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + yy_state_t *yyss1 = yyss; + YYSTYPE *yyvs1 = yyvs; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * YYSIZEOF (*yyssp), + &yyvs1, yysize * YYSIZEOF (*yyvsp), + &yystacksize); + yyss = yyss1; + yyvs = yyvs1; + } +# else /* defined YYSTACK_RELOCATE */ + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + YYNOMEM; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yy_state_t *yyss1 = yyss; + union yyalloc *yyptr = + YY_CAST (union yyalloc *, + YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); + if (! yyptr) + YYNOMEM; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YY_IGNORE_USELESS_CAST_BEGIN + YYDPRINTF ((stderr, "Stack size increased to %ld\n", + YY_CAST (long, yystacksize))); + YY_IGNORE_USELESS_CAST_END + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } +#endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either empty, or end-of-input, or a valid lookahead. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token\n")); + yychar = yylex (); + } + + if (yychar <= YYEOF) + { + yychar = YYEOF; + yytoken = YYSYMBOL_YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else if (yychar == YYerror) + { + /* The scanner already issued an error message, process directly + to error recovery. But do not keep the error token as + lookahead, it is too special and may lead us to an endless + loop in error recovery. */ + yychar = YYUNDEF; + yytoken = YYSYMBOL_YYerror; + goto yyerrlab1; + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + /* Discard the shifted token. */ + yychar = YYEMPTY; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: /* start: %empty */ +#line 101 "hl/src//H5LTparse.y" + { memset(arr_stack, 0, STACK_SIZE*sizeof(struct arr_info)); /*initialize here?*/ } +#line 1353 "hl/src//H5LTparse.c" + break; + + case 3: /* start: ddl_type */ +#line 102 "hl/src//H5LTparse.y" + { return (yyval.hid);} +#line 1359 "hl/src//H5LTparse.c" + break; + + case 13: /* integer_type: H5T_STD_I8BE_TOKEN */ +#line 116 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I8BE); } +#line 1365 "hl/src//H5LTparse.c" + break; + + case 14: /* integer_type: H5T_STD_I8LE_TOKEN */ +#line 117 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I8LE); } +#line 1371 "hl/src//H5LTparse.c" + break; + + case 15: /* integer_type: H5T_STD_I16BE_TOKEN */ +#line 118 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I16BE); } +#line 1377 "hl/src//H5LTparse.c" + break; + + case 16: /* integer_type: H5T_STD_I16LE_TOKEN */ +#line 119 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I16LE); } +#line 1383 "hl/src//H5LTparse.c" + break; + + case 17: /* integer_type: H5T_STD_I32BE_TOKEN */ +#line 120 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I32BE); } +#line 1389 "hl/src//H5LTparse.c" + break; + + case 18: /* integer_type: H5T_STD_I32LE_TOKEN */ +#line 121 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I32LE); } +#line 1395 "hl/src//H5LTparse.c" + break; + + case 19: /* integer_type: H5T_STD_I64BE_TOKEN */ +#line 122 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I64BE); } +#line 1401 "hl/src//H5LTparse.c" + break; + + case 20: /* integer_type: H5T_STD_I64LE_TOKEN */ +#line 123 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_I64LE); } +#line 1407 "hl/src//H5LTparse.c" + break; + + case 21: /* integer_type: H5T_STD_U8BE_TOKEN */ +#line 124 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U8BE); } +#line 1413 "hl/src//H5LTparse.c" + break; + + case 22: /* integer_type: H5T_STD_U8LE_TOKEN */ +#line 125 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U8LE); } +#line 1419 "hl/src//H5LTparse.c" + break; + + case 23: /* integer_type: H5T_STD_U16BE_TOKEN */ +#line 126 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U16BE); } +#line 1425 "hl/src//H5LTparse.c" + break; + + case 24: /* integer_type: H5T_STD_U16LE_TOKEN */ +#line 127 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U16LE); } +#line 1431 "hl/src//H5LTparse.c" + break; + + case 25: /* integer_type: H5T_STD_U32BE_TOKEN */ +#line 128 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U32BE); } +#line 1437 "hl/src//H5LTparse.c" + break; + + case 26: /* integer_type: H5T_STD_U32LE_TOKEN */ +#line 129 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U32LE); } +#line 1443 "hl/src//H5LTparse.c" + break; + + case 27: /* integer_type: H5T_STD_U64BE_TOKEN */ +#line 130 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U64BE); } +#line 1449 "hl/src//H5LTparse.c" + break; + + case 28: /* integer_type: H5T_STD_U64LE_TOKEN */ +#line 131 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_STD_U64LE); } +#line 1455 "hl/src//H5LTparse.c" + break; + + case 29: /* integer_type: H5T_NATIVE_CHAR_TOKEN */ +#line 132 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_CHAR); } +#line 1461 "hl/src//H5LTparse.c" + break; + + case 30: /* integer_type: H5T_NATIVE_SCHAR_TOKEN */ +#line 133 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_SCHAR); } +#line 1467 "hl/src//H5LTparse.c" + break; + + case 31: /* integer_type: H5T_NATIVE_UCHAR_TOKEN */ +#line 134 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_UCHAR); } +#line 1473 "hl/src//H5LTparse.c" + break; + + case 32: /* integer_type: H5T_NATIVE_SHORT_TOKEN */ +#line 135 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_SHORT); } +#line 1479 "hl/src//H5LTparse.c" + break; + + case 33: /* integer_type: H5T_NATIVE_USHORT_TOKEN */ +#line 136 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_USHORT); } +#line 1485 "hl/src//H5LTparse.c" + break; + + case 34: /* integer_type: H5T_NATIVE_INT_TOKEN */ +#line 137 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_INT); } +#line 1491 "hl/src//H5LTparse.c" + break; + + case 35: /* integer_type: H5T_NATIVE_UINT_TOKEN */ +#line 138 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_UINT); } +#line 1497 "hl/src//H5LTparse.c" + break; + + case 36: /* integer_type: H5T_NATIVE_LONG_TOKEN */ +#line 139 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_LONG); } +#line 1503 "hl/src//H5LTparse.c" + break; + + case 37: /* integer_type: H5T_NATIVE_ULONG_TOKEN */ +#line 140 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_ULONG); } +#line 1509 "hl/src//H5LTparse.c" + break; + + case 38: /* integer_type: H5T_NATIVE_LLONG_TOKEN */ +#line 141 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_LLONG); } +#line 1515 "hl/src//H5LTparse.c" + break; + + case 39: /* integer_type: H5T_NATIVE_ULLONG_TOKEN */ +#line 142 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_ULLONG); } +#line 1521 "hl/src//H5LTparse.c" + break; + + case 40: /* fp_type: H5T_IEEE_F32BE_TOKEN */ +#line 145 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_IEEE_F32BE); } +#line 1527 "hl/src//H5LTparse.c" + break; + + case 41: /* fp_type: H5T_IEEE_F32LE_TOKEN */ +#line 146 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_IEEE_F32LE); } +#line 1533 "hl/src//H5LTparse.c" + break; + + case 42: /* fp_type: H5T_IEEE_F64BE_TOKEN */ +#line 147 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_IEEE_F64BE); } +#line 1539 "hl/src//H5LTparse.c" + break; + + case 43: /* fp_type: H5T_IEEE_F64LE_TOKEN */ +#line 148 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_IEEE_F64LE); } +#line 1545 "hl/src//H5LTparse.c" + break; + + case 44: /* fp_type: H5T_NATIVE_FLOAT_TOKEN */ +#line 149 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_FLOAT); } +#line 1551 "hl/src//H5LTparse.c" + break; + + case 45: /* fp_type: H5T_NATIVE_DOUBLE_TOKEN */ +#line 150 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_DOUBLE); } +#line 1557 "hl/src//H5LTparse.c" + break; + + case 46: /* fp_type: H5T_NATIVE_LDOUBLE_TOKEN */ +#line 151 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tcopy(H5T_NATIVE_LDOUBLE); } +#line 1563 "hl/src//H5LTparse.c" + break; + + case 47: /* $@1: %empty */ +#line 155 "hl/src//H5LTparse.y" + { csindex++; cmpd_stack[csindex].id = H5Tcreate(H5T_COMPOUND, 1); /*temporarily set size to 1*/ } +#line 1569 "hl/src//H5LTparse.c" + break; + + case 48: /* compound_type: H5T_COMPOUND_TOKEN $@1 '{' memb_list '}' */ +#line 157 "hl/src//H5LTparse.y" + { (yyval.hid) = cmpd_stack[csindex].id; + cmpd_stack[csindex].id = 0; + cmpd_stack[csindex].first_memb = 1; + csindex--; + } +#line 1579 "hl/src//H5LTparse.c" + break; + + case 51: /* $@2: %empty */ +#line 166 "hl/src//H5LTparse.y" + { cmpd_stack[csindex].is_field = 1; /*notify lexer a compound member is parsed*/ } +#line 1585 "hl/src//H5LTparse.c" + break; + + case 52: /* memb_def: ddl_type $@2 field_name field_offset ';' */ +#line 168 "hl/src//H5LTparse.y" + { + size_t origin_size, new_size; + hid_t dtype_id = cmpd_stack[csindex].id; + + /*Adjust size and insert member, consider both member size and offset.*/ + if(cmpd_stack[csindex].first_memb) { /*reclaim the size 1 temporarily set*/ + new_size = H5Tget_size((yyvsp[-4].hid)) + (yyvsp[-1].ival); + H5Tset_size(dtype_id, new_size); + /*member name is saved in yylval.sval by lexer*/ + H5Tinsert(dtype_id, (yyvsp[-2].sval), (yyvsp[-1].ival), (yyvsp[-4].hid)); + + cmpd_stack[csindex].first_memb = 0; + } else { + origin_size = H5Tget_size(dtype_id); + + if((yyvsp[-1].ival) == 0) { + new_size = origin_size + H5Tget_size((yyvsp[-4].hid)); + H5Tset_size(dtype_id, new_size); + H5Tinsert(dtype_id, (yyvsp[-2].sval), origin_size, (yyvsp[-4].hid)); + } else { + new_size = (yyvsp[-1].ival) + H5Tget_size((yyvsp[-4].hid)); + H5Tset_size(dtype_id, new_size); + H5Tinsert(dtype_id, (yyvsp[-2].sval), (yyvsp[-1].ival), (yyvsp[-4].hid)); + } + } + if((yyvsp[-2].sval)) { + free((yyvsp[-2].sval)); + (yyvsp[-2].sval) = NULL; + } + cmpd_stack[csindex].is_field = 0; + H5Tclose((yyvsp[-4].hid)); + + new_size = H5Tget_size(dtype_id); + } +#line 1624 "hl/src//H5LTparse.c" + break; + + case 53: /* field_name: STRING */ +#line 204 "hl/src//H5LTparse.y" + { + (yyval.sval) = strdup(yylval.sval); + free(yylval.sval); + yylval.sval = NULL; + } +#line 1634 "hl/src//H5LTparse.c" + break; + + case 54: /* field_offset: %empty */ +#line 211 "hl/src//H5LTparse.y" + { (yyval.ival) = 0; } +#line 1640 "hl/src//H5LTparse.c" + break; + + case 55: /* field_offset: ':' offset */ +#line 213 "hl/src//H5LTparse.y" + { (yyval.ival) = yylval.ival; } +#line 1646 "hl/src//H5LTparse.c" + break; + + case 57: /* $@3: %empty */ +#line 217 "hl/src//H5LTparse.y" + { asindex++; /*pushd onto the stack*/ } +#line 1652 "hl/src//H5LTparse.c" + break; + + case 58: /* array_type: H5T_ARRAY_TOKEN $@3 '{' dim_list ddl_type '}' */ +#line 219 "hl/src//H5LTparse.y" + { + (yyval.hid) = H5Tarray_create2((yyvsp[-1].hid), arr_stack[asindex].ndims, arr_stack[asindex].dims); + arr_stack[asindex].ndims = 0; + asindex--; + H5Tclose((yyvsp[-1].hid)); + } +#line 1663 "hl/src//H5LTparse.c" + break; + + case 61: /* $@4: %empty */ +#line 229 "hl/src//H5LTparse.y" + { arr_stack[asindex].is_dim = 1; /*notice lexer of dimension size*/ } +#line 1669 "hl/src//H5LTparse.c" + break; + + case 62: /* $@5: %empty */ +#line 230 "hl/src//H5LTparse.y" + { unsigned ndims = arr_stack[asindex].ndims; + arr_stack[asindex].dims[ndims] = (hsize_t)yylval.ival; + arr_stack[asindex].ndims++; + arr_stack[asindex].is_dim = 0; + } +#line 1679 "hl/src//H5LTparse.c" + break; + + case 65: /* vlen_type: H5T_VLEN_TOKEN '{' ddl_type '}' */ +#line 241 "hl/src//H5LTparse.y" + { (yyval.hid) = H5Tvlen_create((yyvsp[-1].hid)); H5Tclose((yyvsp[-1].hid)); } +#line 1685 "hl/src//H5LTparse.c" + break; + + case 66: /* @6: %empty */ +#line 247 "hl/src//H5LTparse.y" + { + size_t size = (size_t)yylval.ival; + (yyval.hid) = H5Tcreate(H5T_OPAQUE, size); + } +#line 1694 "hl/src//H5LTparse.c" + break; + + case 67: /* $@7: %empty */ +#line 252 "hl/src//H5LTparse.y" + { + H5Tset_tag((yyvsp[-3].hid), yylval.sval); + free(yylval.sval); + yylval.sval = NULL; + } +#line 1704 "hl/src//H5LTparse.c" + break; + + case 68: /* opaque_type: H5T_OPAQUE_TOKEN '{' OPQ_SIZE_TOKEN opaque_size ';' @6 OPQ_TAG_TOKEN opaque_tag ';' $@7 '}' */ +#line 257 "hl/src//H5LTparse.y" + { (yyval.hid) = (yyvsp[-5].hid); } +#line 1710 "hl/src//H5LTparse.c" + break; + + case 71: /* $@8: %empty */ +#line 266 "hl/src//H5LTparse.y" + { + if((yyvsp[-1].ival) == H5T_VARIABLE_TOKEN) + is_variable = 1; + else + str_size = yylval.ival; + } +#line 1721 "hl/src//H5LTparse.c" + break; + + case 72: /* $@9: %empty */ +#line 273 "hl/src//H5LTparse.y" + { + if((yyvsp[-1].ival) == H5T_STR_NULLTERM_TOKEN) + str_pad = H5T_STR_NULLTERM; + else if((yyvsp[-1].ival) == H5T_STR_NULLPAD_TOKEN) + str_pad = H5T_STR_NULLPAD; + else if((yyvsp[-1].ival) == H5T_STR_SPACEPAD_TOKEN) + str_pad = H5T_STR_SPACEPAD; + } +#line 1734 "hl/src//H5LTparse.c" + break; + + case 73: /* $@10: %empty */ +#line 282 "hl/src//H5LTparse.y" + { + if((yyvsp[-1].ival) == H5T_CSET_ASCII_TOKEN) + str_cset = H5T_CSET_ASCII; + else if((yyvsp[-1].ival) == H5T_CSET_UTF8_TOKEN) + str_cset = H5T_CSET_UTF8; + } +#line 1745 "hl/src//H5LTparse.c" + break; + + case 74: /* @11: %empty */ +#line 289 "hl/src//H5LTparse.y" + { + if((yyvsp[-1].hid) == H5T_C_S1_TOKEN) + (yyval.hid) = H5Tcopy(H5T_C_S1); + else if((yyvsp[-1].hid) == H5T_FORTRAN_S1_TOKEN) + (yyval.hid) = H5Tcopy(H5T_FORTRAN_S1); + } +#line 1756 "hl/src//H5LTparse.c" + break; + + case 75: /* string_type: H5T_STRING_TOKEN '{' STRSIZE_TOKEN strsize ';' $@8 STRPAD_TOKEN strpad ';' $@9 CSET_TOKEN cset ';' $@10 CTYPE_TOKEN ctype ';' @11 '}' */ +#line 296 "hl/src//H5LTparse.y" + { + hid_t str_id = (yyvsp[-1].hid); + + /*set string size*/ + if(is_variable) { + H5Tset_size(str_id, H5T_VARIABLE); + is_variable = 0; + } else + H5Tset_size(str_id, str_size); + + /*set string padding and character set*/ + H5Tset_strpad(str_id, str_pad); + H5Tset_cset(str_id, str_cset); + + (yyval.hid) = str_id; + } +#line 1777 "hl/src//H5LTparse.c" + break; + + case 76: /* strsize: H5T_VARIABLE_TOKEN */ +#line 313 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_VARIABLE_TOKEN;} +#line 1783 "hl/src//H5LTparse.c" + break; + + case 78: /* strpad: H5T_STR_NULLTERM_TOKEN */ +#line 316 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_STR_NULLTERM_TOKEN;} +#line 1789 "hl/src//H5LTparse.c" + break; + + case 79: /* strpad: H5T_STR_NULLPAD_TOKEN */ +#line 317 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_STR_NULLPAD_TOKEN;} +#line 1795 "hl/src//H5LTparse.c" + break; + + case 80: /* strpad: H5T_STR_SPACEPAD_TOKEN */ +#line 318 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_STR_SPACEPAD_TOKEN;} +#line 1801 "hl/src//H5LTparse.c" + break; + + case 81: /* cset: H5T_CSET_ASCII_TOKEN */ +#line 320 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_CSET_ASCII_TOKEN;} +#line 1807 "hl/src//H5LTparse.c" + break; + + case 82: /* cset: H5T_CSET_UTF8_TOKEN */ +#line 321 "hl/src//H5LTparse.y" + {(yyval.ival) = H5T_CSET_UTF8_TOKEN;} +#line 1813 "hl/src//H5LTparse.c" + break; + + case 83: /* ctype: H5T_C_S1_TOKEN */ +#line 323 "hl/src//H5LTparse.y" + {(yyval.hid) = H5T_C_S1_TOKEN;} +#line 1819 "hl/src//H5LTparse.c" + break; + + case 84: /* ctype: H5T_FORTRAN_S1_TOKEN */ +#line 324 "hl/src//H5LTparse.y" + {(yyval.hid) = H5T_FORTRAN_S1_TOKEN;} +#line 1825 "hl/src//H5LTparse.c" + break; + + case 85: /* $@12: %empty */ +#line 328 "hl/src//H5LTparse.y" + { is_enum = 1; enum_id = H5Tenum_create((yyvsp[-1].hid)); H5Tclose((yyvsp[-1].hid)); } +#line 1831 "hl/src//H5LTparse.c" + break; + + case 86: /* enum_type: H5T_ENUM_TOKEN '{' integer_type ';' $@12 enum_list '}' */ +#line 330 "hl/src//H5LTparse.y" + { is_enum = 0; /*reset*/ (yyval.hid) = enum_id; } +#line 1837 "hl/src//H5LTparse.c" + break; + + case 89: /* $@13: %empty */ +#line 335 "hl/src//H5LTparse.y" + { + is_enum_memb = 1; /*indicate member of enum*/ + enum_memb_symbol = strdup(yylval.sval); + free(yylval.sval); + yylval.sval = NULL; + } +#line 1848 "hl/src//H5LTparse.c" + break; + + case 90: /* enum_def: enum_symbol $@13 enum_val ';' */ +#line 342 "hl/src//H5LTparse.y" + { + char char_val=(char)yylval.ival; + short short_val=(short)yylval.ival; + int int_val=(int)yylval.ival; + long long_val=(long)yylval.ival; + long long llong_val=(long long)yylval.ival; + hid_t super = H5Tget_super(enum_id); + hid_t native = H5Tget_native_type(super, H5T_DIR_ASCEND); + H5T_order_t super_order = H5Tget_order(super); + H5T_order_t native_order = H5Tget_order(native); + + if(is_enum && is_enum_memb) { /*if it's an enum member*/ + /*To handle machines of different endianness*/ + if(H5Tequal(native, H5T_NATIVE_SCHAR) || H5Tequal(native, H5T_NATIVE_UCHAR)) { + if(super_order != native_order) + H5Tconvert(native, super, 1, &char_val, NULL, H5P_DEFAULT); + H5Tenum_insert(enum_id, enum_memb_symbol, &char_val); + } else if(H5Tequal(native, H5T_NATIVE_SHORT) || H5Tequal(native, H5T_NATIVE_USHORT)) { + if(super_order != native_order) + H5Tconvert(native, super, 1, &short_val, NULL, H5P_DEFAULT); + H5Tenum_insert(enum_id, enum_memb_symbol, &short_val); + } else if(H5Tequal(native, H5T_NATIVE_INT) || H5Tequal(native, H5T_NATIVE_UINT)) { + if(super_order != native_order) + H5Tconvert(native, super, 1, &int_val, NULL, H5P_DEFAULT); + H5Tenum_insert(enum_id, enum_memb_symbol, &int_val); + } else if(H5Tequal(native, H5T_NATIVE_LONG) || H5Tequal(native, H5T_NATIVE_ULONG)) { + if(super_order != native_order) + H5Tconvert(native, super, 1, &long_val, NULL, H5P_DEFAULT); + H5Tenum_insert(enum_id, enum_memb_symbol, &long_val); + } else if(H5Tequal(native, H5T_NATIVE_LLONG) || H5Tequal(native, H5T_NATIVE_ULLONG)) { + if(super_order != native_order) + H5Tconvert(native, super, 1, &llong_val, NULL, H5P_DEFAULT); + H5Tenum_insert(enum_id, enum_memb_symbol, &llong_val); + } + + is_enum_memb = 0; + if(enum_memb_symbol) free(enum_memb_symbol); + } + + H5Tclose(super); + H5Tclose(native); + } +#line 1895 "hl/src//H5LTparse.c" + break; + + +#line 1899 "hl/src//H5LTparse.c" + + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", YY_CAST (yysymbol_kind_t, yyr1[yyn]), &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + + *++yyvsp = yyval; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + { + const int yylhs = yyr1[yyn] - YYNTOKENS; + const int yyi = yypgoto[yylhs] + *yyssp; + yystate = (0 <= yyi && yyi <= YYLAST && yycheck[yyi] == *yyssp + ? yytable[yyi] + : yydefgoto[yylhs]); + } + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYSYMBOL_YYEMPTY : YYTRANSLATE (yychar); + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; + yyerror (YY_("syntax error")); + } + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + /* Pacify compilers when the user code never invokes YYERROR and the + label yyerrorlab therefore never appears in user code. */ + if (0) + YYERROR; + ++yynerrs; + + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + /* Pop stack until we find a state that shifts the error token. */ + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYSYMBOL_YYerror; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYSYMBOL_YYerror) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + YY_ACCESSING_SYMBOL (yystate), yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", YY_ACCESSING_SYMBOL (yyn), yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturnlab; + + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturnlab; + + +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + goto yyreturnlab; + + +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + YY_ACCESSING_SYMBOL (+*yyssp), yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif + + return yyresult; +} + diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/config/CompilerFlagsHelpers.cmake b/modules/drivers/highfive/HighFive-2.7.1/CMake/config/CompilerFlagsHelpers.cmake deleted file mode 100644 index e3755ad8c..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/CMake/config/CompilerFlagsHelpers.cmake +++ /dev/null @@ -1,59 +0,0 @@ -# CompilerFlagsHelpers.cmake -# -# set of Convenience functions for portable compiler flags -# -# License: BSD 3 -# -# Copyright (c) 2016, Adrien Devresse -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -set(SUPPORTED_COMPILER_LANGUAGE_LIST "C;CXX") - -foreach(COMPILER_LANGUAGE ${SUPPORTED_COMPILER_LANGUAGE_LIST}) - - # XLC compiler - if(CMAKE_${COMPILER_LANGUAGE}_COMPILER_ID MATCHES "XL") - - # XLC -qinfo=all is awfully verbose on any platforms that use the GNU STL - # Enable by default only the relevant one - set(CMAKE_${COMPILER_LANGUAGE}_WARNING_ALL "-qformat=all -qinfo=lan:trx:ret:zea:cmp:ret") - - ## GCC, CLANG, rest of the world - elseif(CMAKE_${COMPILER_LANGUAGE}_COMPILER_ID MATCHES "Clang" - OR CMAKE_${COMPILER_LANGUAGE}_COMPILER_ID MATCHES "GNU" - OR CMAKE_${COMPILER_LANGUAGE}_COMPILER_ID MATCHES "Intel") - set(CMAKE_${COMPILER_LANGUAGE}_WARNING_ALL " -Wall -Wextra") - string(CONCAT CMAKE_${COMPILER_LANGUAGE}_WARNING_DEBUG - " -Werror -Wshadow -Wnon-virtual-dtor -Wunused -Woverloaded-virtual" - " -Wformat=2 -Wconversion -Wsign-conversion -Wno-error=deprecated-declarations" - ) - if(NOT CMAKE_${COMPILER_LANGUAGE}_COMPILER_IS_ICC) - string(CONCAT CMAKE_${COMPILER_LANGUAGE}_WARNING_DEBUG - ${CMAKE_${COMPILER_LANGUAGE}_WARNING_DEBUG} - " -Wpedantic -Wcast-align -Wdouble-promotion" - ) - endif() - endif() - - if(CMAKE_${COMPILER_LANGUAGE}_COMPILER_ID MATCHES "GNU" - AND (CMAKE_${COMPILER_LANGUAGE}_COMPILER_VERSION VERSION_GREATER "4.7.0")) - set(CMAKE_${COMPILER_LANGUAGE}_WARNING_ALL - "${CMAKE_${COMPILER_LANGUAGE}_WARNING_ALL} -Wno-unused-parameter") - endif() - -endforeach() - - - diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/config/ReleaseDebugAutoFlags.cmake b/modules/drivers/highfive/HighFive-2.7.1/CMake/config/ReleaseDebugAutoFlags.cmake deleted file mode 100644 index 2b980698e..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/CMake/config/ReleaseDebugAutoFlags.cmake +++ /dev/null @@ -1,45 +0,0 @@ -# ReleaseDebugAutoFlags.cmake -# -# Release / Debug configuration helper -# -# License: BSD 3 -# -# Copyright (c) 2016, Adrien Devresse -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -## default configuration -if(NOT CMAKE_BUILD_TYPE AND (NOT CMAKE_CONFIGURATION_TYPES)) - set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE) - message(STATUS "Setting build type to '${CMAKE_BUILD_TYPE}' as none was specified.") -endif() - - -# Different configuration types: -# -# Debug : Optimized for debugging, include symbols -# Release : Release mode, no debuginfo -# RelWithDebInfo : Distribution mode, basic optimizations for potable code with debuginfos - -include(CompilerFlagsHelpers) - - -string(APPEND CMAKE_C_FLAGS_RELEASE "${CMAKE_C_WARNING_ALL}") -string(APPEND CMAKE_C_FLAGS_DEBUG "${CMAKE_C_WARNING_ALL}" "${CMAKE_C_WARNING_DEBUG}") -string(APPEND CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_WARNING_ALL}" "${CMAKE_C_WARNING_DEBUG}") - - -string(APPEND CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_WARNING_ALL}") -string(APPEND CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_WARNING_ALL}" "${CMAKE_CXX_WARNING_DEBUG}") -string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_WARNING_ALL}" "${CMAKE_C_WARNING_DEBUG}") diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_eigen.cpp b/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_eigen.cpp deleted file mode 100644 index 9c21dbc73..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_eigen.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include - -#define H5_USE_EIGEN 1 - -#include -#include - -using namespace HighFive; - -void data_io(void) { - const std::string DATASET_NAME("dset"); - const int nrows = 10; - const int ncols = 3; - - try { - Eigen::MatrixXd mat(nrows, ncols); - - for (int i = 0; i < nrows; ++i) { - for (int j = 0; j < ncols; ++j) { - mat(i, j) = double(j + i * 100); - } - } - - File file("eigen_mat.h5", File::ReadWrite | File::Create | File::Truncate); - - DataSet dset = file.createDataSet(DATASET_NAME, mat); - dset.write(mat); - - Eigen::MatrixXd result; - dset.read(result); - - } catch (const Exception& err) { - std::cerr << err.what() << std::endl; - } -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Attribute.hpp b/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Attribute.hpp deleted file mode 100644 index c20b6c8f2..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Attribute.hpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c), 2017, Ali Can Demiralp - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#pragma once - -#include - -#include - -#include "H5DataType.hpp" -#include "H5Object.hpp" -#include "bits/H5Friends.hpp" -#include "bits/H5Path_traits.hpp" - -namespace HighFive { -class DataSpace; - -namespace detail { - -/// \brief Internal hack to create an `Attribute` from an ID. -/// -/// WARNING: Creating an Attribute from an ID has implications w.r.t. the lifetime of the object -/// that got passed via its ID. Using this method careless opens up the suite of issues -/// related to C-style resource management, including the analog of double free, dangling -/// pointers, etc. -/// -/// NOTE: This is not part of the API and only serves to work around a compiler issue in GCC which -/// prevents us from using `friend`s instead. This function should only be used for internal -/// purposes. The problematic construct is: -/// -/// template -/// friend class SomeCRTP; -/// -/// \private -Attribute make_attribute(hid_t hid); -} // namespace detail - -/// -/// \brief Class representing an attribute of a dataset or group -/// -class Attribute: public Object, public PathTraits { - public: - const static ObjectType type = ObjectType::Attribute; - - /// - /// \brief return the name of the current attribute - /// \return the name of the attribute - std::string getName() const; - - size_t getStorageSize() const; - - /// - /// \brief getDataType - /// \return return the datatype associated with this dataset - /// - DataType getDataType() const; - - /// - /// \brief getSpace - /// \return return the dataspace associated with this dataset - /// - DataSpace getSpace() const; - - /// - /// \brief getMemSpace - /// \return same than getSpace for DataSet, compatibility with Selection - /// class - /// - DataSpace getMemSpace() const; - - /// \brief Return the attribute - template - T read() const; - - /// - /// Read the attribute into a buffer - /// An exception is raised if the numbers of dimension of the buffer and of - /// the attribute are different - /// - /// The array type can be a N-pointer or a N-vector ( e.g int** integer two - /// dimensional array ) - template - void read(T& array) const; - - /// \brief Read the attribute into a buffer - template - void read(T* array, const DataType& dtype = {}) const; - - /// - /// Write the integrality N-dimension buffer to this attribute - /// An exception is raised if the numbers of dimension of the buffer and of - /// the attribute are different - /// - /// The array type can be a N-pointer or a N-vector ( e.g int** integer two - /// dimensional array ) - template - void write(const T& buffer); - - /// \brief Write a buffer to this attribute - template - void write_raw(const T* buffer, const DataType& dtype = {}); - - /// \brief Get the list of properties for creation of this attribute - AttributeCreateProps getCreatePropertyList() const { - return details::get_plist(*this, H5Aget_create_plist); - } - - // No empty attributes - Attribute() = delete; - - protected: - using Object::Object; - - private: -#if HIGHFIVE_HAS_FRIEND_DECLARATIONS - template - friend class ::HighFive::AnnotateTraits; -#endif - - friend Attribute detail::make_attribute(hid_t); -}; - -namespace detail { -inline Attribute make_attribute(hid_t hid) { - return Attribute(hid); -} -} // namespace detail - -} // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataSpace.hpp b/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataSpace.hpp deleted file mode 100644 index 9c1647205..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataSpace.hpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#pragma once - -#include -#include -#include -#include -#include - -#include "H5Object.hpp" -#include "bits/H5_definitions.hpp" - -namespace HighFive { - -/// -/// \brief Class representing the space (dimensions) of a dataset -/// -class DataSpace: public Object { - public: - const static ObjectType type = ObjectType::DataSpace; - - static const size_t UNLIMITED = SIZE_MAX; - - /// dataspace type - enum DataspaceType { - dataspace_scalar, - dataspace_null - // simple dataspace are handle directly from their dimensions - }; - - /// create a dataspace of N-dimensions - /// Each dimension is configured this way - /// size(dim1) = vec[0] - /// size(dim2) = vec[1] - /// etc... - explicit DataSpace(const std::vector& dims); - - // create a dataspace of N-dimensions - template - explicit DataSpace(const std::array& dims); - - /// Make sure that DataSpace({1,2,3}) works on GCC. This is - /// the shortcut form of the vector initializer, but one some compilers (gcc) - /// this does not resolve correctly without this constructor. - DataSpace(const std::initializer_list& items); - - /// Allow directly listing 1 or more dimensions to initialize, - /// that is, DataSpace(1,2) means DataSpace(std::vector{1,2}). - template - explicit DataSpace(size_t dim1, Args... dims); - - /// Create a dataspace from an iterator pair - /// - /// Explicitly disable DataSpace(int_like, int_like) from trying to use this constructor - template ::value, IT>::type> - DataSpace(const IT begin, const IT end); - - /// \brief Create a resizable N-dimensional dataspace - /// \param dims Initial size of dataspace - /// \param maxdims Maximum size of the dataspace - explicit DataSpace(const std::vector& dims, const std::vector& maxdims); - - /// - /// \brief DataSpace create a scalar dataspace or a null dataset - /// - explicit DataSpace(DataspaceType dtype); - - /// Create a new DataSpace - /// with a different id available for modifications - DataSpace clone() const; - - /// - /// \brief getNumberDimensions - /// \return the number of dimensions in the current dataspace - /// - size_t getNumberDimensions() const; - - /// \brief getDimensions - /// \return return a vector of N-element, each element is the size of the - /// associated dataset dimension - std::vector getDimensions() const; - - /// \brief getElementCount - /// \return the total number of elements in the dataspace - size_t getElementCount() const; - - /// \brief getMaxDimensions - /// \return return a vector of N-element, each element is the size of the - /// associated dataset maximum dimension - std::vector getMaxDimensions() const; - - /// Create a dataspace matching a type accepted by details::inspector - template - static DataSpace From(const T& value); - - template - static DataSpace FromCharArrayStrings(const char (&)[N][Width]); - - protected: - DataSpace() = default; - - friend class Attribute; - friend class File; - friend class DataSet; -}; - -} // namespace HighFive - -// We include bits right away since DataSpace is user-constructible -#include "bits/H5Dataspace_misc.hpp" diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multi_array_2D.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multi_array_2D.cpp deleted file mode 100644 index 29ce9f451..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multi_array_2D.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include - -#undef H5_USE_BOOST -#define H5_USE_BOOST - -#include -#include - -using namespace HighFive; - -const std::string FILE_NAME("boost_multiarray_example.h5"); -const std::string DATASET_NAME("dset"); -const int size_x = 10; -const int size_y = 3; - -// Create a 2D dataset 10x3 of double with boost multi array -// and write it to a file -int main(void) { - try { - boost::multi_array my_array(boost::extents[size_x][size_y]); - - for (int i = 0; i < size_x; ++i) { - for (int j = 0; j < size_y; ++j) { - my_array[i][j] = double(j + i * size_y); - } - } - - // we create a new hdf5 file - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // let's create our dataset of the size of the boost::multi_array - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(my_array)); - - // we fill it - dataset.write(my_array); - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_attribute_string_integer.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_attribute_string_integer.cpp deleted file mode 100644 index 564901bda..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_attribute_string_integer.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include -#include - -using namespace HighFive; - -const std::string FILE_NAME("create_attribute.h5"); -const std::string DATASET_NAME("my_dataset"); - -const std::string ATTRIBUTE_NAME_NOTE("note"); -const std::string ATTRIBUTE_NAME_VERSION("version_string"); - -// create a dataset from a vector of string -// read it back and print it -int main(void) { - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Create a dummy dataset of one single integer - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(1), create_datatype()); - - // Now let's add a attribute on this dataset - // This attribute will be named "note" - // and have the following content - std::string string_list("very important Dataset !"); - - Attribute a = dataset.createAttribute(ATTRIBUTE_NAME_NOTE, - DataSpace::From(string_list)); - a.write(string_list); - - // We also add a "version" attribute - // that will be an array 1x2 of integer - std::vector version; - version.push_back(1); - version.push_back(0); // version 1.0 - - Attribute v = dataset.createAttribute(ATTRIBUTE_NAME_VERSION, - DataSpace::From(version)); - v.write(version); - - // Ok all attributes are now written - - // let's list the keys of all attributes now - std::vector all_attributes_keys = dataset.listAttributeNames(); - for (const auto& attr: all_attributes_keys) { - std::cout << "attribute: " << attr << std::endl; - } - - } catch (const Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_double.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_double.cpp deleted file mode 100644 index ba7f4bc03..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_double.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("create_dataset_example.h5"); -const std::string DATASET_NAME("dset"); - -// Create a dataset name "dset" of double 4x6 -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Define the size of our dataset: 2x6 - std::vector dims{2, 6}; - - // Create the dataset - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(dims)); - - double data[2][6] = {{1.1, 2.2, 3.3, 4.4, 5.5, 6.6}, - {11.11, 12.12, 13.13, 14.14, 15.15, 16.16}}; - - // write it - dataset.write(data); - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_half_float.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_half_float.cpp deleted file mode 100644 index c73d00994..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_dataset_half_float.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c), 2022, Blue Brain Project - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ - -#ifdef H5_USE_HALF_FLOAT - -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("create_dataset_half_float_example.h5"); -const std::string DATASET_NAME("dset"); - -// Create a dataset name "dset", size 4x6, and type float16_t (i.e., 16-bit half-precision -// floating-point format) -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Define the size of our dataset: 4x6 - std::vector dims{4, 6}; - - // Create the dataset - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(dims)); - - std::vector> data; - for (size_t i = 0; i < 4; ++i) { - data.emplace_back(); - for (size_t j = 0; j < 6; ++j) - data[i].emplace_back((i + 1) * (j + 1)); - } - - // write it - dataset.write(data); - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} - -#endif \ No newline at end of file diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_datatype.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_datatype.cpp deleted file mode 100644 index c7aa1bfbe..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_datatype.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include - -#include -#include - -using namespace HighFive; - -static const std::string FILE_NAME("create_datatype_example.h5"); -static const std::string DATASET_NAME("test_dataset"); - - -// Struct representation of custom type (type v below) -typedef struct { - char a; - short b; - unsigned long long c; -} csl; - -bool operator==(csl x, csl y) { - return x.a == y.a && x.b == y.b && x.c == y.c; -} - -bool operator!=(csl x, csl y) { - return !(x == y); -} - -// Tell HighFive how to create the HDF5 datatype for this base type by -// using the HIGHFIVE_REGISTER_TYPE macro -CompoundType create_compound_csl() { - return {{"u1", create_datatype()}, - {"u2", create_datatype()}, - {"u3", create_datatype()}}; -} -HIGHFIVE_REGISTER_TYPE(csl, create_compound_csl) - -int main(void) { - try { - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Create a simple compound type with automatic alignment of the - // members. For this the type alignment is trivial. - std::vector t_members( - {{"real", create_datatype()}, {"imag", create_datatype()}}); - CompoundType t(t_members); - t.commit(file, "new_type1"); - - // Create a complex nested datatype with manual alignment - CompoundType u({{"u1", t, 0}, {"u2", t, 9}, {"u3", create_datatype(), 20}}, 26); - u.commit(file, "new_type3"); - - // Create a more complex type with automatic alignment. For this the - // type alignment is more complex. - CompoundType v_aligned{{"u1", create_datatype()}, - {"u2", create_datatype()}, - {"u3", create_datatype()}}; - // introspect the compound type - std::cout << "v_aligned size: " << v_aligned.getSize(); - for (const auto& member: v_aligned.getMembers()) { - std::cout << " field " << member.name << " offset: " << member.offset << std::endl; - } - - v_aligned.commit(file, "new_type2_aligned"); - - // Create a more complex type with a fully packed alignment. The - // equivalent type is created with a standard struct alignment in the - // implementation of HighFive::create_datatype above - CompoundType v_packed({{"u1", create_datatype(), 0}, - {"u2", create_datatype(), 1}, - {"u3", create_datatype(), 3}}, - 11); - v_packed.commit(file, "new_type2_packed"); - - - // Initialise some data - std::vector data; - data.push_back({'f', 1, 4}); - data.push_back({'g', -4, 18}); - - // Write the data into the file in a fully packed form - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(2), v_packed); - dataset.write(data); - - file.flush(); - - // Read a subset of the data back - std::vector result; - dataset.select({0}, {2}).read(result); - - for (size_t i = 0; i < data.size(); ++i) { - if (result[i] != data[i]) { - std::cout << "result[" << i << "]:" << std::endl; - std::cout << " " << result[i].a << std::endl; - std::cout << " " << result[i].b << std::endl; - std::cout << " " << result[i].c << std::endl; - std::cout << "data[" << i << "]:" << std::endl; - std::cout << " " << data[i].a << std::endl; - std::cout << " " << data[i].b << std::endl; - std::cout << " " << data[i].c << std::endl; - } - } - - - } catch (const Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - return 1; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_extensible_dataset.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_extensible_dataset.cpp deleted file mode 100644 index 96dc2a11b..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_extensible_dataset.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("create_extensible_dataset_example.h5"); -const std::string DATASET_NAME("dset"); - -// Create a dataset name "dset" of double 4x6 -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Create a dataspace with initial shape and max shape - DataSpace dataspace = DataSpace({4, 5}, {17, DataSpace::UNLIMITED}); - - // Use chunking - DataSetCreateProps props; - props.add(Chunking(std::vector{2, 2})); - - // Create the dataset - DataSet dataset = - file.createDataSet(DATASET_NAME, dataspace, create_datatype(), props); - - // Write into the initial part of the dataset - double t1[3][1] = {{2.0}, {2.0}, {4.0}}; - dataset.select({0, 0}, {3, 1}).write(t1); - - // Resize the dataset to a larger size - dataset.resize({4, 6}); - - // Write into the new part of the dataset - double t2[1][3] = {{4.0, 8.0, 6.0}}; - dataset.select({3, 3}, {1, 3}).write(t2); - - // now we read it back - std::vector> result; - dataset.read(result); - - // we print it out and see: - // 2 0 0 0 0 0 - // 2 0 0 0 0 0 - // 4 0 0 0 0 0 - // 0 0 0 4 8 6 - for (auto row: result) { - for (auto col: row) - std::cout << " " << col; - std::cout << std::endl; - } - - } catch (const Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/eigen_matrix.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/eigen_matrix.cpp deleted file mode 100644 index 50c3d40b2..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/eigen_matrix.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * Copyright (c), 2022, Blue Brain Project - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include - -#ifdef H5_USE_EIGEN - -#include -#include - -using namespace HighFive; - -const std::string FILE_NAME("eigen_matrix_example.h5"); -const std::string DATASET_NAME("dset"); -const int nrows = 10; -const int ncols = 3; - -// Create a 2D dataset 10x3 of double with eigen matrix -// and write it to a file -int main(void) { - try { - Eigen::MatrixXd matrix(nrows, ncols); - - for (int i = 0; i < nrows; ++i) { - for (int j = 0; j < ncols; ++j) { - matrix(i, j) = double(j + i * 100); - } - } - - // we create a new hdf5 file - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // let's create our dataset of the size of the eigen matrix - file.createDataSet(DATASET_NAME, matrix); - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} - -#endif diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/hl_hdf5_inmemory_files.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/hl_hdf5_inmemory_files.cpp deleted file mode 100644 index 212e64ec5..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/hl_hdf5_inmemory_files.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c), 2022, Blue Brain Project - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include - - -#include -#include - -using namespace HighFive; - -class InMemoryFile: public HighFive::File { - public: - explicit InMemoryFile(std::vector buffer) - : _buffer(std::move(buffer)) { - _hid = H5LTopen_file_image(_buffer.data(), - sizeof(_buffer[0]) * _buffer.size(), - H5LT_FILE_IMAGE_DONT_RELEASE | H5LT_FILE_IMAGE_DONT_COPY); - } - - private: - std::vector _buffer; -}; - - -// Create a 2D dataset 10x3 of double with eigen matrix -// and write it to a file -int main(void) { - const std::string FILE_NAME("inmemory_file.h5"); - const std::string DATASET_NAME("dset"); - - try { - auto data = std::vector{1.0, 2.0, 3.0}; - - { - // We create an HDF5 file. - File file(FILE_NAME, File::Truncate); - file.createDataSet(DATASET_NAME, data); - } - - // Simulate having an inmemory file by reading a file - // byte-by-byte into RAM. - auto buffer = std::vector(1ul << 20); - auto file = std::fopen(FILE_NAME.c_str(), "r"); - auto nread = std::fread(buffer.data(), sizeof(buffer[0]), buffer.size(), file); - std::cout << "Bytes read: " << nread << "\n"; - - // Create a file from a buffer. - auto h5 = InMemoryFile(std::move(buffer)); - - // Read a dataset as usual. - auto read_back = h5.getDataSet(DATASET_NAME).read>(); - - // Check if the values match. - for (size_t i = 0; i < read_back.size(); ++i) { - if (read_back[i] != data[i]) { - throw std::runtime_error("Values don't match."); - } else { - std::cout << "read_back[" << i << "] = " << read_back[i] << "\n"; - } - } - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} \ No newline at end of file diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_dataset_string.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_dataset_string.cpp deleted file mode 100644 index ec1813eb2..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_dataset_string.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -using namespace HighFive; - -const std::string FILE_NAME("create_dataset_string_example.h5"); -const std::string DATASET_NAME("story"); - -// create a dataset from a vector of string -// read it back and print it -int main(void) { - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - std::vector string_list; - string_list.push_back("Hello World !"); - string_list.push_back( - "This string list is mapped to a dataset of " - "variable length string"); - string_list.push_back("Encoding is done in UTF-8 - 你好 - Здравствуйте!"); - string_list.push_back("May the force be with you"); - string_list.push_back("Enjoy !"); - - // create a dataset ready to contains strings of the size of the vector - // string_list - DataSet dataset = file.createDataSet(DATASET_NAME, - DataSpace::From(string_list)); - - // let's write our vector of string - dataset.write(string_list); - - // now we read it back - std::vector result_string_list; - dataset.read(result_string_list); - - for (size_t i = 0; i < result_string_list.size(); ++i) { - std::cout << ":" << i << " " << result_string_list[i] << "\n"; - } - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_fixedlen_string.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_fixedlen_string.cpp deleted file mode 100644 index 1d13f97bc..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_fixedlen_string.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c), 2020, Blue Brain Project - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -using namespace HighFive; - -static const std::string FILE_NAME("create_dataset_string_example.h5"); - -// create a dataset from a vector of string -// read it back and print it -int main(void) { - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - const char strings_fixed[][16] = {"abcabcabcabcabc", "123123123123123"}; - - // create a dataset ready to contains strings of the size of the vector - file.createDataSet("ds1", DataSpace(2)).write(strings_fixed); - - // Without specific type info this will create an int8 dataset - file.createDataSet("ds2", strings_fixed); - - // Now test the new interface type - FixedLenStringArray<10> arr{"0000000", "1111111"}; // also accepts std::vector - auto ds = file.createDataSet("ds3", arr); - - // Read back truncating to 4 chars - FixedLenStringArray<4> array_back; - ds.read(array_back); - std::cout << "First item is '" << array_back[0] << "'" << std::endl - << "Second item is '" << array_back[1] << "'" << std::endl; - - - } catch (const Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_raw_ptr.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_raw_ptr.cpp deleted file mode 100644 index bef55278b..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_raw_ptr.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * Copyright (c), 2022, Blue Brain Project - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("read_write_raw_ptr.h5"); -const std::string DATASET_NAME("array"); - -// This create a "multi-dimensional" array. Meaning a pointer with -// dimensions. The `std::vector` is mearly a convenient way -// of allocating and releasing memory. -// -// Conceptionually this is only a raw pointer with dimensions. The -// data is store in row-major, aka C-style, without stride, offset -// or padding. -std::vector make_array(const std::vector& dims) { - auto n_elements = dims[0] * dims[1]; - std::vector nd_array(n_elements, 0.0); - - for (size_t i = 0; i < dims[0]; ++i) { - for (size_t j = 0; j < dims[1]; ++j) { - nd_array[j + i * dims[1]] = double(j) + 100.0 * double(i); - } - } - - return nd_array; -} - -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // Let's write to file. - { - std::vector dims{3, 5}; - auto nd_array = make_array(dims); - - // First, create a dataset with the correct dimensions. - auto dataset = file.createDataSet(DATASET_NAME, DataSpace(dims)); - - // Then write, using the raw pointer. - dataset.write_raw(nd_array.data()); - } - - // Let's read from file. - { - auto dataset = file.getDataSet(DATASET_NAME); - - // First read the dimensions. - auto dims = dataset.getDimensions(); - - // Then allocate memory. - auto n_elements = dims[0] * dims[1]; - auto nd_array = std::vector(n_elements); - - // Finally, read into the memory by passing a raw pointer to the library. - dataset.read(nd_array.data()); - } - - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_single_scalar.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_single_scalar.cpp deleted file mode 100644 index ed0492d68..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_single_scalar.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("read_write_scalar.h5"); -const std::string DATASET_NAME("single_scalar"); - -// Create a dataset name "single_scalar" -// which contains only the perfect integer number "42" -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - int perfect_number = 42; - - // Create the dataset - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(perfect_number)); - - // write it - dataset.write(perfect_number); - - // flush everything - file.flush(); - - // let's read it back - int potentially_perfect_number; - - dataset.read(potentially_perfect_number); - - std::cout << "perfect number: " << potentially_perfect_number << std::endl; - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_by_id_dataset_cpp11.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_by_id_dataset_cpp11.cpp deleted file mode 100644 index 794168919..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_by_id_dataset_cpp11.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("select_partial_string.h5"); -const std::string DATASET_NAME("message"); - -// Create a dataset name "dset" of double 4x6 -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - { - // We have a set of string - std::vector values = { - "Cat", - "Dog", - "Hello", - "Tree", - "World", - "Plane", - ", ", - "你好", - "Tea", - "Moon", - "صباح جميل", - "Spaceship", - }; - - // let's create a dataset - DataSet dataset = file.createDataSet(DATASET_NAME, - DataSpace::From(values)); - - // and write them - dataset.write(values); - } - - { - DataSet dataset = file.getDataSet(DATASET_NAME); - - // now let's read back by cherry pick our interesting string - std::vector result; - // we select only element N° 2 and 5 - dataset.select(ElementSet({2, 4, 6, 7, 6, 10})).read(result); - - // and display it - for (auto i: result) { - std::cout << i << " "; - } - std::cout << "\n"; - } - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_partial_dataset_cpp11.cpp b/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_partial_dataset_cpp11.cpp deleted file mode 100644 index dce12fde7..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/select_partial_dataset_cpp11.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c), 2017, Adrien Devresse - * - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - * - */ -#include -#include -#include -#include - -#include -#include -#include - -const std::string FILE_NAME("select_partial_example.h5"); -const std::string DATASET_NAME("dset"); - -// Create a dataset name "dset" of double 4x6 -// -int main(void) { - using namespace HighFive; - try { - // Create a new file using the default property lists. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); - - // we have some example values in a 2D vector 2x5 - std::vector> values = {{1.0, 2.0, 4.0, 8.0, 16.0}, - {32.0, 64.0, 128.0, 256.0, 512.0}}; - - // let's create a dataset of this size - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(values)); - // and write them - dataset.write(values); - - // now we read back 2x2 values after an offset of 0x2 - std::vector> result; - dataset.select({0, 2}, {2, 2}).read(result); - - // we print out 4 values - for (auto i: result) { - for (auto j: i) { - std::cout << " " << j; - } - std::cout << "\n"; - } - - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated -} diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/include/simpleton.hpp b/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/include/simpleton.hpp deleted file mode 100644 index 0684294d0..000000000 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/include/simpleton.hpp +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef H5_TEST_SIMPLETON_HPP -#define H5_TEST_SIMPLETON_HPP - -// Include all headers here to catch any missing `inline` statements, since -// they will be included by two different compilation units. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// Boost should always be found in this setup -#include - -void function(const HighFive::Object& obj); -void other_function(const boost::numeric::ublas::matrix& m); - -#endif diff --git a/modules/drivers/highfive/HighFive-2.7.1.zip b/modules/drivers/highfive/HighFive-2.8.0.zip similarity index 67% rename from modules/drivers/highfive/HighFive-2.7.1.zip rename to modules/drivers/highfive/HighFive-2.8.0.zip index 560c224ac..a1471cfe0 100644 Binary files a/modules/drivers/highfive/HighFive-2.7.1.zip and b/modules/drivers/highfive/HighFive-2.8.0.zip differ diff --git a/modules/drivers/highfive/HighFive-2.7.1/.clang-format b/modules/drivers/highfive/HighFive-2.8.0/.clang-format similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.clang-format rename to modules/drivers/highfive/HighFive-2.8.0/.clang-format diff --git a/modules/drivers/highfive/HighFive-2.7.1/.git-blame-ignore-revs b/modules/drivers/highfive/HighFive-2.8.0/.git-blame-ignore-revs similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.git-blame-ignore-revs rename to modules/drivers/highfive/HighFive-2.8.0/.git-blame-ignore-revs diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/bug_report.md b/modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/bug_report.md rename to modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/bug_report.md diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/config.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/config.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/config.yml diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/feature_request.md b/modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/ISSUE_TEMPLATE/feature_request.md rename to modules/drivers/highfive/HighFive-2.8.0/.github/ISSUE_TEMPLATE/feature_request.md diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/build.sh b/modules/drivers/highfive/HighFive-2.8.0/.github/build.sh similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/build.sh rename to modules/drivers/highfive/HighFive-2.8.0/.github/build.sh diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/pull_request_template.md b/modules/drivers/highfive/HighFive-2.8.0/.github/pull_request_template.md similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/pull_request_template.md rename to modules/drivers/highfive/HighFive-2.8.0/.github/pull_request_template.md diff --git a/modules/drivers/highfive/HighFive-2.8.0/.github/run_examples.sh b/modules/drivers/highfive/HighFive-2.8.0/.github/run_examples.sh new file mode 100644 index 000000000..77861f388 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/run_examples.sh @@ -0,0 +1,20 @@ +#! /usr/bin/env bash + +set -e + +if [[ $# -eq 0 ]] +then + examples_dir="." +elif [[ $# -eq 1 ]] +then + examples_dir="$1" +else + echo "Usage: $0 [EXAMPLES_DIR]" + exit -1 +fi + +for f in "${examples_dir}"/*_bin +do + echo "-- ${f}" + "${f}" +done diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/check_doxygen_awesome_version.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/check_doxygen_awesome_version.yml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/check_doxygen_awesome_version.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/check_doxygen_awesome_version.yml diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/ci.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/ci.yml similarity index 75% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/ci.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/ci.yml index 4ae0a0b4b..e7f5fca10 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/ci.yml +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/ci.yml @@ -54,6 +54,9 @@ jobs: os: ubuntu-20.04 pkgs: 'libboost-all-dev' flags: '-DCMAKE_CXX_STANDARD=17' + - config: + os: ubuntu-22.04 + flags: '-DHIGHFIVE_USE_BOOST=Off -DCMAKE_CXX_STANDARD=20' steps: - uses: actions/checkout@v3 @@ -77,7 +80,7 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build - run: ctest --output-on-failure -C $BUILD_TYPE + run: ctest -j2 --output-on-failure -C $BUILD_TYPE # Job testing several versions of hdf5 @@ -86,7 +89,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - hdf5_version : [ hdf5-1_8_23, hdf5-1_10_9, hdf5-1_12_2, hdf5-1_14_0 ] + hdf5_version : [ hdf5-1_8_23, hdf5-1_10_11, hdf5-1_12_2, hdf5-1_14_3 ] steps: - uses: actions/checkout@v3 @@ -102,18 +105,25 @@ jobs: wget https://github.com/HDFGroup/hdf5/archive/refs/tags/${{ matrix.hdf5_version }}.tar.gz --output-document hdf5.tar.gz tar xf hdf5.tar.gz mkdir -p hdf5-${{ matrix.hdf5_version }}/BUILD && cd hdf5-${{ matrix.hdf5_version }}/BUILD - cmake .. -GNinja -DCMAKE_INSTALL_PREFIX=$HOME/${{ matrix.hdf5_version }} -DHDF5_ENABLE_Z_LIB_SUPPORT=ON -DUSE_LIBAEC=ON + cmake .. -DCMAKE_BUILD_TYPE=Release -GNinja -DCMAKE_INSTALL_PREFIX=$HOME/${{ matrix.hdf5_version }} -DHDF5_ENABLE_Z_LIB_SUPPORT=ON -DUSE_LIBAEC=ON -DHDF5_BUILD_EXAMPLES=OFF -DBUILD_STATIC_LIBS=OFF -DBUILD_TESTING=OFF ninja && ninja install - name: Build run: | - mkdir BUILD && cd BUILD - cmake -GNinja -DHDF5_ROOT=$HOME/${{ matrix.hdf5_version }} .. - ninja + CMAKE_OPTIONS=( + -GNinja + -DHDF5_ROOT=$HOME/${{ matrix.hdf5_version }} + ) + source $GITHUB_WORKSPACE/.github/build.sh - name: Test - run: | - cd BUILD && ctest --output-on-failure + working-directory: ${{github.workspace}}/build + run: ctest -j2 --output-on-failure -C $BUILD_TYPE + + + - name: Examples + working-directory: ${{github.workspace}}/build/src/examples + run: $GITHUB_WORKSPACE/.github/run_examples.sh # Job testing several compilers on a stable Linux # ==================================================== @@ -146,7 +156,11 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build - run: ctest --output-on-failure -C $BUILD_TYPE + run: ctest -j2 --output-on-failure -C $BUILD_TYPE + + - name: Examples + working-directory: ${{github.workspace}}/build/src/examples + run: $GITHUB_WORKSPACE/.github/run_examples.sh # Job running unit-test with sanitizers # ===================================== @@ -185,22 +199,43 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build - run: ctest --output-on-failure -C $BUILD_TYPE + run: ctest -j2 --output-on-failure -C $BUILD_TYPE + + - name: Examples + working-directory: ${{github.workspace}}/build/src/examples + run: $GITHUB_WORKSPACE/.github/run_examples.sh # Job to check using HighFive from other CMake projects # ===================================================== CMake_Project: runs-on: ubuntu-20.04 + strategy: + matrix: + parallelism: [ serial, parallel ] steps: - uses: actions/checkout@v3 with: submodules: true - - name: "Install libraries" + - name: "Update Ubuntu" run: | sudo apt-get -qq update - sudo apt-get -qq install libboost-all-dev libhdf5-dev libsz2 ninja-build + + - name: "Install common libraries" + run: | + sudo apt-get -qq install libboost-all-dev libsz2 ninja-build + + - name: "Install serial HDF5" + if: matrix.parallelism == 'serial' + run: | + sudo apt-get -qq install libhdf5-dev + + + - name: "Install parallel HDF5" + if: matrix.parallelism == 'parallel' + run: | + sudo apt-get -qq install libhdf5-openmpi-dev - name: "CMake Project Integration" run: bash tests/test_project_integration.sh @@ -230,7 +265,11 @@ jobs: # Job testing in OSX # ================== OSX: - runs-on: macOS-12 + runs-on: ${{matrix.os}} + strategy: + matrix: + os: [ "macOS-12" ] + cxxstd: ["14", "17", "20"] steps: - uses: actions/checkout@v3 @@ -250,29 +289,44 @@ jobs: -DHIGHFIVE_BUILD_DOCS:BOOL=FALSE -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON -DCMAKE_CXX_FLAGS="-coverage -O0" + -DCMAKE_CXX_STANDARD=${{matrix.cxxstd}} ) source $GITHUB_WORKSPACE/.github/build.sh - name: Test working-directory: ${{github.workspace}}/build - run: ctest --output-on-failure -C $BUILD_TYPE + run: ctest -j2 --output-on-failure -C $BUILD_TYPE + + - name: Examples + working-directory: ${{github.workspace}}/build/src/examples + run: $GITHUB_WORKSPACE/.github/run_examples.sh # Job testing in Windows # ====================== - Windows-2022: + Windows: runs-on: ${{matrix.os}} strategy: matrix: os: [ "windows-2022"] vs-toolset: [ "v141", "v143" ] - cxxstd: ["14", "17"] + cxxstd: ["14", "17", "20"] + + include: + - os: "windows-2019" + vs-toolset: "v142" + cxxstd: "14" + + - os: "windows-2019" + vs-toolset: "v142" + cxxstd: "17" + steps: - uses: actions/checkout@v3 with: submodules: true - - uses: mamba-org/provision-with-micromamba@main + - uses: mamba-org/setup-micromamba@v1 with: environment-file: doc/environment.yaml environment-name: win-test @@ -294,41 +348,4 @@ jobs: - name: Test working-directory: ${{github.workspace}}/build shell: bash -l {0} - run: ctest --output-on-failure -C $BUILD_TYPE - - Windows-2019: - runs-on: ${{matrix.os}} - strategy: - matrix: - os: [ "windows-2019"] - vs-toolset: [ "v142" ] - cxxstd: ["14", "17"] - steps: - - uses: actions/checkout@v3 - with: - submodules: true - - - uses: mamba-org/provision-with-micromamba@main - with: - environment-file: doc/environment.yaml - environment-name: win-test - - - name: Build - shell: bash -l {0} - run: | - CMAKE_OPTIONS=( - -T ${{matrix.vs-toolset}} - -DCMAKE_CXX_STANDARD=${{matrix.cxxstd}} - -DHIGHFIVE_UNIT_TESTS=ON - -DHIGHFIVE_USE_BOOST:BOOL=ON - -DHIGHFIVE_USE_EIGEN:BOOL=ON - -DHIGHFIVE_USE_XTENSOR:BOOL=ON - -DHIGHFIVE_TEST_SINGLE_INCLUDES=ON - ) - source $GITHUB_WORKSPACE/.github/build.sh - - - name: Test - working-directory: ${{github.workspace}}/build - shell: bash -l {0} - run: ctest --output-on-failure -C $BUILD_TYPE - + run: ctest -j2 --output-on-failure -C $BUILD_TYPE diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/clang_format.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/clang_format.yml similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/clang_format.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/clang_format.yml index 99cb6e1b3..56f2fd8d5 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/clang_format.yml +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/clang_format.yml @@ -32,5 +32,8 @@ jobs: then echo "Some files are not well formatted:" echo $modified_files + echo "" + echo "The diff is:" + git diff exit 1 fi diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/coverage.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/coverage.yml similarity index 73% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/coverage.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/coverage.yml index 020bc5f7e..b3f4a212b 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/coverage.yml +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/coverage.yml @@ -41,7 +41,7 @@ jobs: fetch-depth: 2 submodules: true - - name: Build and test for code coverage + - name: Build for code coverage run: | CMAKE_OPTIONS=( -GNinja @@ -54,14 +54,15 @@ jobs: -DCMAKE_CXX_FLAGS="-coverage -O0" ) source $GITHUB_WORKSPACE/.github/build.sh - cd $HIGHFIVE_BUILD - (cd $GITHUB_WORKSPACE; lcov --capture --initial --directory . --no-external --output-file build/coverage-base.info) - cmake --build $HIGHFIVE_BUILD --target test - (cd $GITHUB_WORKSPACE; lcov --capture --directory . --no-external --output-file build/coverage-run.info) - lcov --add-tracefile coverage-base.info --add-tracefile coverage-run.info --output-file coverage-combined.info + - name: Test for code coverage + run: | + lcov --capture --initial --directory . --no-external --output-file build/coverage-base.info + (cd build; cmake --build . --target test) + lcov --capture --directory . --no-external --output-file build/coverage-run.info + (cd build; lcov --add-tracefile coverage-base.info --add-tracefile coverage-run.info --output-file coverage-combined.info) - uses: codecov/codecov-action@v3 with: files: ./build/coverage-combined.info - fail_ci_if_error: true + fail_ci_if_error: false verbose: true token: ${{ secrets.CODECOV_TOKEN }} diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/gh-pages.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/gh-pages.yml similarity index 94% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/gh-pages.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/gh-pages.yml index 117836fd5..2032f91ab 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/gh-pages.yml +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/gh-pages.yml @@ -24,7 +24,7 @@ jobs: with: submodules: 'recursive' - - uses: mamba-org/provision-with-micromamba@main + - uses: mamba-org/setup-micromamba@v1 with: environment-file: doc/environment.yaml environment-name: doc-build diff --git a/modules/drivers/highfive/HighFive-2.7.1/.github/workflows/integration_trigger.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/integration_trigger.yml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.github/workflows/integration_trigger.yml rename to modules/drivers/highfive/HighFive-2.8.0/.github/workflows/integration_trigger.yml diff --git a/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/version_file.yml b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/version_file.yml new file mode 100644 index 000000000..816137e95 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/.github/workflows/version_file.yml @@ -0,0 +1,36 @@ +name: HighFive Check Version File + +on: + push: + branches: + - ci_test + - release/** + pull_request: + branches: + - master + - release/** + +jobs: + CheckVersion: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + - name: "Install libraries" + run: | + sudo apt-get -qq update + sudo apt-get -qq install libhdf5-dev ninja-build + + - name: Build + run: | + # Will trigger `configure_file` for H5Version.hpp. + cmake -DHIGHFIVE_USE_BOOST=Off -B build . + + - name: Test + run: | + # Check that the file hasn't changed, i.e. was updated + # after changing the version number. + ! git status | grep include/highfive/H5Version.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/.gitignore b/modules/drivers/highfive/HighFive-2.8.0/.gitignore similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.gitignore rename to modules/drivers/highfive/HighFive-2.8.0/.gitignore diff --git a/modules/drivers/highfive/HighFive-2.7.1/.gitmodules b/modules/drivers/highfive/HighFive-2.8.0/.gitmodules similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.gitmodules rename to modules/drivers/highfive/HighFive-2.8.0/.gitmodules diff --git a/modules/drivers/highfive/HighFive-2.7.1/.travis.yml b/modules/drivers/highfive/HighFive-2.8.0/.travis.yml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/.travis.yml rename to modules/drivers/highfive/HighFive-2.8.0/.travis.yml diff --git a/modules/drivers/highfive/HighFive-2.7.1/AUTHORS.txt b/modules/drivers/highfive/HighFive-2.8.0/AUTHORS.txt similarity index 92% rename from modules/drivers/highfive/HighFive-2.7.1/AUTHORS.txt rename to modules/drivers/highfive/HighFive-2.8.0/AUTHORS.txt index 11d03032f..78f573a9a 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/AUTHORS.txt +++ b/modules/drivers/highfive/HighFive-2.8.0/AUTHORS.txt @@ -2,6 +2,7 @@ Adrien Devresse Alexandru Săvulescu Ali Can Demiralp Angelos Plastropoulos +@antonysigma Chris Byrohl Chris De Grendele @contre @@ -12,6 +13,8 @@ Fernando L. Pereira @guoxy Haoran Ni Henry Schreiner +@hn-sl +Hunter Belanger @JaWSnl Jia Li John W. Peterson @@ -36,6 +39,7 @@ Pablo Toharia Philip Deegan Philipp Gloor Pramod Kumbhar +@Quark-X10 Richard Shaw Rick Nitsche Rob Latham @@ -48,6 +52,7 @@ Tino Wagner Tobias Klauser Tom de Geus Tom Vander Aa +Torsten Reuschel Tristan Carel Wolf Vollprecht Y. Yang diff --git a/modules/drivers/highfive/HighFive-2.7.1/CHANGELOG.md b/modules/drivers/highfive/HighFive-2.8.0/CHANGELOG.md similarity index 86% rename from modules/drivers/highfive/HighFive-2.7.1/CHANGELOG.md rename to modules/drivers/highfive/HighFive-2.8.0/CHANGELOG.md index f6d03a438..9a8cd8613 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/CHANGELOG.md +++ b/modules/drivers/highfive/HighFive-2.8.0/CHANGELOG.md @@ -1,3 +1,34 @@ +# Changes +## Version 2.8.0 - 2023-11-02 +### Important Change + - `Eigen::Matrix` is (by default) stored with column-major index ordering. Under + certain conditions `Eigen::Matrix` was written and read as row-major. + Due to code duplication H5Easy isn't affected by this bug. Starting + `2.8.0` HighFive will now throw an exception whenever prior versions would + have read with incorrect assumptions about the index ordering. (#731) + +### New Features + - Improve reading and writing `std::string` as fixed and variable length HDF5 strings (#744). + - Implement creation of hard links (#765). Thanks to @Quark-X10. + - Get the size of file and amound of tracked unused space (#764). Thanks to @Quark-X10. + - `class DataType` has a new ctor to open a commited `DataType` (#796). Thanks to @Quark-X10. + - Allow user-specified `mem_space` for hyperslabs. (#740) + - New properties: `AttributePhaseChange`. (#785) + - New options to link against HDF5 statically (#823). Thanks @HunterBelanger. + - Add support for `std::complex` valid with C++23 (#828). Thanks @unbtorsten. + - Add a top-level header to include all compononents (#818). + +### Improvements + - Add concept checks to `Property` if C++20 for better errors (#811). Thanks @antonysigma. + - Add parallel HDF5 test in CI (#760). + - Simplify github workflow (#761). + - Move inspectors in their own file to be able to better implements strings (#759). + +### Bug Fix + - Fix vector constructor ambiguity in H5DataType.hpp (#775). Thanks to @hn-sl. + - `getElementCount()` fixed. (#787) + - Remove leak when calling dtor of `CompoundType`. (#798) + ## Version 2.7.1 - 2023-04-04 ### Bug Fix - Revert removing `#include "H5FileDriver.hpp"` from `H5File.hpp` (#711). diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveConfig.cmake.in b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveConfig.cmake.in similarity index 93% rename from modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveConfig.cmake.in rename to modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveConfig.cmake.in index 370e82863..464a645d0 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveConfig.cmake.in +++ b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveConfig.cmake.in @@ -15,6 +15,8 @@ if(TARGET HighFive) return() endif() +@PACKAGE_INIT@ + # Get HighFive targets include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargets.cmake") @@ -61,8 +63,12 @@ if(HIGHFIVE_USE_XTENSOR AND NOT CMAKE_VERSION VERSION_LESS 3.8) set_property(TARGET HighFive APPEND PROPERTY INTERFACE_COMPILE_FEATURES cxx_std_14) endif() -message(STATUS "HIGHFIVE @PROJECT_VERSION@: (Re)Detecting Highfive dependencies (HIGHFIVE_USE_INSTALL_DEPS=NO)") +if(NOT HighFive_FIND_QUIETLY) + message(STATUS "HIGHFIVE @PROJECT_VERSION@: (Re)Detecting Highfive dependencies (HIGHFIVE_USE_INSTALL_DEPS=NO)") +endif() include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargetDeps.cmake") foreach(dependency HighFive_libheaders libdeps) copy_interface_properties(HighFive ${dependency}) endforeach() + +check_required_components(HighFive) diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetDeps.cmake b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetDeps.cmake similarity index 96% rename from modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetDeps.cmake rename to modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetDeps.cmake index 8fddf39e7..919b53544 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetDeps.cmake +++ b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetDeps.cmake @@ -26,6 +26,7 @@ if(NOT TARGET libdeps) # HDF5 if(NOT DEFINED HDF5_C_LIBRARIES) set(HDF5_PREFER_PARALLEL ${HIGHFIVE_PARALLEL_HDF5}) + set(HDF5_USE_STATIC_LIBRARIES ${HIGHFIVE_STATIC_HDF5}) find_package(HDF5 REQUIRED) endif() @@ -36,6 +37,8 @@ if(NOT TARGET libdeps) target_include_directories(libdeps SYSTEM INTERFACE ${HDF5_INCLUDE_DIRS}) target_link_libraries(libdeps INTERFACE ${HDF5_LIBRARIES}) target_compile_definitions(libdeps INTERFACE ${HDF5_DEFINITIONS}) + target_compile_definitions(libdeps INTERFACE HIGHFIVE_HAS_CONCEPTS=$) + # Boost if(HIGHFIVE_USE_BOOST) diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetExport.cmake b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetExport.cmake similarity index 96% rename from modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetExport.cmake rename to modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetExport.cmake index 011f7f483..9906f3951 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/CMake/HighFiveTargetExport.cmake +++ b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveTargetExport.cmake @@ -4,7 +4,6 @@ add_library(libheaders INTERFACE) target_include_directories(libheaders INTERFACE "$" - "$" "$") # Combined HighFive diff --git a/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveWarnings.cmake b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveWarnings.cmake new file mode 100644 index 000000000..8e8ec2201 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/CMake/HighFiveWarnings.cmake @@ -0,0 +1,36 @@ +if(TARGET HighFiveWarnings) + # Allow multiple `include(HighFiveWarnings)`, which would + # attempt to redefine `HighFiveWarnings` and fail without + # this check. + return() +endif() + +add_library(HighFiveWarnings INTERFACE) + +if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" + OR CMAKE_CXX_COMPILER_ID MATCHES "GNU" + OR CMAKE_CXX_COMPILER_ID MATCHES "Intel") + + target_compile_options(HighFiveWarnings + INTERFACE + -Wall + -Wextra + -Wshadow + -Wnon-virtual-dtor + -Wunused + -Woverloaded-virtual + -Wformat=2 + -Wconversion + -Wsign-conversion + -Wno-error=deprecated-declarations + ) + + if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Intel") + target_compile_options(HighFiveWarnings + INTERFACE + -Wpedantic + -Wcast-align + -Wdouble-promotion + ) + endif() +endif() diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMake/config/TestHelpers.cmake b/modules/drivers/highfive/HighFive-2.8.0/CMake/config/TestHelpers.cmake similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/CMake/config/TestHelpers.cmake rename to modules/drivers/highfive/HighFive-2.8.0/CMake/config/TestHelpers.cmake diff --git a/modules/drivers/highfive/HighFive-2.7.1/CMakeLists.txt b/modules/drivers/highfive/HighFive-2.8.0/CMakeLists.txt similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/CMakeLists.txt rename to modules/drivers/highfive/HighFive-2.8.0/CMakeLists.txt index 7c8bbd803..af274d9e2 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/CMakeLists.txt +++ b/modules/drivers/highfive/HighFive-2.8.0/CMakeLists.txt @@ -5,15 +5,14 @@ else() cmake_policy(VERSION 3.13) endif() -project(HighFive VERSION 2.7.1) +project(HighFive VERSION 2.8.0) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp.in - ${CMAKE_CURRENT_BINARY_DIR}/include/highfive/H5Version.hpp) + ${CMAKE_CURRENT_SOURCE_DIR}/include/highfive/H5Version.hpp) # INCLUDES list(APPEND CMAKE_MODULE_PATH - ${PROJECT_SOURCE_DIR}/CMake - ${PROJECT_SOURCE_DIR}/CMake/portability - ${PROJECT_SOURCE_DIR}/CMake/config) + ${CMAKE_CURRENT_SOURCE_DIR}/CMake + ${CMAKE_CURRENT_SOURCE_DIR}/CMake/config) # OPTIONS # Compatibility within Highfive 2.x series @@ -33,9 +32,11 @@ option(HIGHFIVE_USE_OPENCV "Enable OpenCV testing" ${USE_OPENCV}) option(HIGHFIVE_USE_XTENSOR "Enable xtensor testing" ${USE_XTENSOR}) option(HIGHFIVE_EXAMPLES "Compile examples" ON) option(HIGHFIVE_PARALLEL_HDF5 "Enable Parallel HDF5 support" OFF) +option(HIGHFIVE_STATIC_HDF5 "Staticly link to HDF5 library" OFF) option(HIGHFIVE_BUILD_DOCS "Enable documentation building" ON) option(HIGHFIVE_VERBOSE "Set logging level to verbose." OFF) option(HIGHFIVE_GLIBCXX_ASSERTIONS "Enable bounds check for STL." OFF) +option(HIGHFIVE_HAS_CONCEPTS "Print readable compiler errors w/ C++20 concepts" ON) # Controls if HighFive classes are friends of each other. # @@ -103,17 +104,12 @@ install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION "include" PATTERN "*.in" EXCLUDE) -# Installation of configured headers -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/include/ - DESTINATION "include") - - # Preparing local building (tests, examples) # ------------------------------------------ # Disable test if Boost was expressly disabled, or if HighFive is a sub-project if (NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) - if(HIGHFIVE_UNIT_TESTS) + if(HIGHFIVE_UNIT_TESTS AND NOT HighFive_FIND_QUIETLY) message(WARNING "Unit tests have been DISABLED.") endif() set(HIGHFIVE_UNIT_TESTS FALSE) @@ -134,15 +130,6 @@ if(HIGHFIVE_UNIT_TESTS) endif() endif() - -if(CMAKE_CXX_COMPILER_ID MATCHES "Intel") - # ICC gets mad if we shorten "int"s - add_definitions("-wd1682") -endif() - -# Set compile time flags _after_ including required dependencies -include(ReleaseDebugAutoFlags) - if(HIGHFIVE_EXAMPLES) add_subdirectory(src/examples) endif() diff --git a/modules/drivers/highfive/HighFive-2.7.1/LICENSE b/modules/drivers/highfive/HighFive-2.8.0/LICENSE similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/LICENSE rename to modules/drivers/highfive/HighFive-2.8.0/LICENSE diff --git a/modules/drivers/highfive/HighFive-2.7.1/README.md b/modules/drivers/highfive/HighFive-2.8.0/README.md similarity index 60% rename from modules/drivers/highfive/HighFive-2.7.1/README.md rename to modules/drivers/highfive/HighFive-2.8.0/README.md index 0ebb8c099..3ea068015 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/README.md +++ b/modules/drivers/highfive/HighFive-2.8.0/README.md @@ -1,6 +1,5 @@ # HighFive - HDF5 header-only C++ Library -[![Build Status](https://travis-ci.org/BlueBrain/HighFive.svg?branch=master)](https://travis-ci.org/BlueBrain/HighFive) [![Doxygen -> gh-pages](https://github.com/BlueBrain/HighFive/workflows/gh-pages/badge.svg)](https://BlueBrain.github.io/HighFive) [![codecov](https://codecov.io/gh/BlueBrain/HighFive/branch/master/graph/badge.svg?token=UBKxHEn7RS)](https://codecov.io/gh/BlueBrain/HighFive) [![HighFive_Integration_tests](https://github.com/BlueBrain/HighFive-testing/actions/workflows/integration.yml/badge.svg)](https://github.com/BlueBrain/HighFive-testing/actions/workflows/integration.yml) @@ -11,12 +10,11 @@ Documentation: https://bluebrain.github.io/HighFive/ HighFive is a modern header-only C++11 friendly interface for libhdf5. -HighFive supports STL vector/string, Boost::UBLAS, Boost::Multi-array, Eigen and Xtensor. It handles C++ from/to HDF5 with automatic type mapping. -HighFive does not require additional libraries (see dependencies) and supports both HDF5 thread safety and Parallel HDF5 (contrary to the official hdf5 cpp) +HighFive supports STL vector/string, Boost::UBLAS, Boost::Multi-array and Xtensor. It handles C++ from/to HDF5 with automatic type mapping. +HighFive does not require additional libraries (see dependencies). It integrates nicely with other CMake projects by defining (and exporting) a HighFive target. - ### Design - Simple C++-ish minimalist interface - No other dependency than libhdf5 @@ -43,13 +41,19 @@ It integrates nicely with other CMake projects by defining (and exporting) a Hig - xtensor (optional, opt-in with -D*HIGHFIVE_USE_XTENSOR*=ON) - half (optional, opt-in with -D*HIGHFIVE_USE_HALF_FLOAT*=ON) +### Known flaws +- HighFive is not thread-safe. At best it has the same limitations as the HDF5 library. However, HighFive objects modify their members without protecting these writes. Users have reported that HighFive is not thread-safe even when using the threadsafe HDF5 library, e.g., https://github.com/BlueBrain/HighFive/discussions/675. +- Eigen support in core HighFive is broken. See https://github.com/BlueBrain/HighFive/issues/532. H5Easy is not + affected. +- The support of fixed length strings isn't ideal. + ## Examples #### Write a std::vector to 1D HDF5 dataset and read it back ```c++ -#include +#include using namespace HighFive; @@ -105,12 +109,6 @@ See [create_attribute_string_integer.cpp](https://github.com/BlueBrain/HighFive/ See [src/examples/](https://github.com/BlueBrain/HighFive/blob/master/src/examples/) subdirectory for more info. -### Compiling with HighFive - -```bash -c++ -o program -I/path/to/highfive/include source.cpp -lhdf5 -``` - ### H5Easy For several 'standard' use cases the [highfive/H5Easy.hpp](include/highfive/H5Easy.hpp) interface is available. It allows: @@ -152,60 +150,98 @@ whereby the `int` type of this example can be replaced by any of the above types ## CMake integration +There's two common paths of integrating HighFive into a CMake based project. +The first is to "vendor" HighFive, the second is to install HighFive as a +normal C++ library. Due to how HighFive CMake code works, sometimes following +the third Bailout Approach is needed. -HighFive can easily be used by other C++ CMake projects. +### Vendoring HighFive -You may use HighFive from a folder in your project (typically a git submodule). +In this approach the HighFive sources are included in a subdirectory of the +project (typically as a git submodule), for example in `third_party/HighFive`. + +The projects `CMakeLists.txt` add the following lines ```cmake -cmake_minimum_required(VERSION 3.1 FATAL_ERROR) -project(foo) -set(CMAKE_CXX_STANDARD 11) +add_executable(foo foo.cpp) + +# You might want to turn off Boost support: +if(NOT DEFINED HIGHFIVE_USE_BOOST) + set(HIGHFIVE_USE_BOOST Off) +endif() -add_subdirectory(highfive_folder) -add_executable(bar bar.cpp) -target_link_libraries(bar HighFive) +# Include the subdirectory and use the target HighFive. +add_subdirectory(third_party/HighFive) +target_link_libraries(foo HighFive) ``` -Alternativelly you can install HighFive once and use it in several projects via `find_package()`. +**Note:** `add_subdirectory(third_party/HighFive)` will search and "link" HDF5 +and optional dependencies such as Boost. -A HighFive target will bring the compilation settings to find HighFive headers and all chosen dependencies. +### Regular Installation of HighFive +Alternatively you can install HighFive once and use it in several projects via +`find_package()`. First one should clone the sources: +```bash +git clone --recursive https://github.com/BlueBrain/HighFive.git HighFive-src +``` +By default CMake will install systemwide, which is likely not appropriate. The +instruction below allow users to select a custom path where HighFive will be +installed, e.g. `HIGHFIVE_INSTALL_PREFIX=${HOME}/third_party/HighFive` or some +other location. The CMake invocations would be +```bash +cmake -DHIGHFIVE_EXAMPLES=Off \ + -DHIGHFIVE_USE_BOOST=Off \ + -DHIGHFIVE_UNIT_TESTS=Off \ + -DCMAKE_INSTALL_PREFIX=${HIGHFIVE_INSTALL_PREFIX} \ + -B HighFive-src/build \ + HighFive-src + +cmake --build HighFive-src/build +cmake --install HighFive-src/build +``` +This will install (i.e. copy) the headers to +`${HIGHFIVE_INSTALL_PREFIX}/include` and some CMake files into an appropriate +subfolder of `${HIGHFIVE_INSTALL_PREFIX}`. + +The projects `CMakeLists.txt` should add the following: ```cmake # ... +add_executable(foo foo.cpp) + find_package(HighFive REQUIRED) -add_executable(bar bar.cpp) -target_link_libraries(bar HighFive) +target_link_libraries(foo HighFive) ``` -**Note:** Like with other libraries you may need to provide CMake the location to find highfive: `CMAKE_PREFIX_PATH=` -**Note:** `find_package(HighFive)` will search dependencies as well (e.g. Boost if requested). In order to use the same dependencies found at HighFive install time (e.g. for system deployments) you may set `HIGHFIVE_USE_INSTALL_DEPS=YES` +**Note:** If HighFive hasn't been installed in a default location, CMake needs +to be told where to find it which can be done by adding +`-DCMAKE_PREFIX_PATH=${HIGHFIVE_INSTALL_PREFIX}` to the CMake command for +building the project using HighFive. The variable `CMAKE_PREFIX_PATH` is a +semi-colon `;` separated list of directories. -### Installing -When installing via CMake, besides the headers, a HighFiveConfig.cmake is generated which provides the HighFive target, as seen before. Note: You may need to set `CMAKE_INSTALL_PREFIX`: -```bash -mkdir build && cd build -# Look up HighFive CMake options, consider inspecting with `ccmake` -cmake .. -DHIGHFIVE_EXAMPLES=OFF -DCMAKE_INSTALL_PREFIX="" -make install -``` +**Note:** `find_package(HighFive)` will search and "link" HDF5 and optional +dependencies such as Boost. -### Test Compilation -As a header-only library, HighFive doesn't require compilation. You may however build tests and examples. +### The Bailout Approach +Since both `add_subdirectory` and `find_package` will trigger finding HDF5 and +other optional dependencies of HighFive as well as the `target_link_libraries` +code for "linking" with the dependencies, things can go wrong. + +Fortunately, HighFive is a header only library and all that's needed is the +headers. Preferably, the version obtained by installing HighFive, since those +include `H5Version.hpp`. Let's assume they've been copied to +`third_party/HighFive`. Then one could create a target: ```bash -mkdir build && cd build -cmake ../ -make # build tests and examples -make test # build and run unit tests -``` +add_library(HighFive INTERFACE) +target_include_directory(HighFive INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/third_party/HighFive/include) -**Note:** Unit tests require Boost. In case it's unavailable you may use `-DHIGHFIVE_USE_BOOST=OFF`. -HighFive with disable support for Boost types as well as unit tests (though most examples will build). -### Code formatting -If you want to propose pull requests to this project, do not forget to format code with -clang-format version 12. -The .clang-format is at the root of the git repository. +add_executable(foo foo.cpp) +target_link_libraries(foo HighFive) +``` + +One known case where this is required is when vendoring the optional +dependencies of HighFive. # Questions? @@ -213,6 +249,8 @@ Do you have questions on how to use HighFive? Would you like to share an interes discuss HighFive features? Head over to the [Discussions](https://github.com/BlueBrain/HighFive/discussions) forum and join the community. +For bugs and issues please use [Issues](https://github.com/BlueBrain/HighFive/issues). + # Funding & Acknowledgment The development of this software was supported by funding to the Blue Brain Project, a research center of the École polytechnique fédérale de Lausanne (EPFL), from the Swiss government's ETH Board of the Swiss Federal Institutes of Technology. diff --git a/modules/drivers/highfive/HighFive-2.8.0/codecov.yml b/modules/drivers/highfive/HighFive-2.8.0/codecov.yml new file mode 100644 index 000000000..bfdc9877d --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/codecov.yml @@ -0,0 +1,8 @@ +coverage: + status: + project: + default: + informational: true + patch: + default: + informational: true diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/CMakeLists.txt b/modules/drivers/highfive/HighFive-2.8.0/doc/CMakeLists.txt similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/CMakeLists.txt rename to modules/drivers/highfive/HighFive-2.8.0/doc/CMakeLists.txt diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/Doxyfile b/modules/drivers/highfive/HighFive-2.8.0/doc/Doxyfile similarity index 99% rename from modules/drivers/highfive/HighFive-2.7.1/doc/Doxyfile rename to modules/drivers/highfive/HighFive-2.8.0/doc/Doxyfile index db9fb98a4..6ebc393ec 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/Doxyfile +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/Doxyfile @@ -865,6 +865,8 @@ WARN_LOGFILE = # Note: If this tag is empty the current directory is searched. INPUT = @CMAKE_CURRENT_SOURCE_DIR@/../include \ + @CMAKE_CURRENT_SOURCE_DIR@/installation.md \ + @CMAKE_CURRENT_SOURCE_DIR@/developer_guide.md \ @CMAKE_CURRENT_SOURCE_DIR@/../CHANGELOG.md \ @CMAKE_CURRENT_SOURCE_DIR@/../README.md diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/DoxygenLayout.xml b/modules/drivers/highfive/HighFive-2.8.0/doc/DoxygenLayout.xml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/DoxygenLayout.xml rename to modules/drivers/highfive/HighFive-2.8.0/doc/DoxygenLayout.xml index 76c566b2d..8fee2ee56 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/DoxygenLayout.xml +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/DoxygenLayout.xml @@ -181,6 +181,7 @@ + @@ -205,7 +206,6 @@ - diff --git a/modules/drivers/highfive/HighFive-2.8.0/doc/developer_guide.md b/modules/drivers/highfive/HighFive-2.8.0/doc/developer_guide.md new file mode 100644 index 000000000..3017289b5 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/developer_guide.md @@ -0,0 +1,93 @@ +# Developer Guide +First clone the repository and remember the `--recursive`: +```bash +git clone --recursive git@github.com:BlueBrain/HighFive.git +``` +The instructions to recover if you forgot are: +```bash +git submodule update --init --recursive +``` + +One remark on submodules: each HighFive commit expects that the submodules are +at a particular commit. The catch is that performing `git checkout` will not +update the submodules automatically. Hence, sometimes a `git submodule update +--recursive` might be needed to checkout the expected version of the +submodules. + +## Compiling and Running the Tests +The instructions for compiling with examples and unit-tests are: + +```bash +cmake -B build -DCMAKE_BUILD_TYPE={Debug,Release} . +cmake --build build --parallel +ctest --test-dir build +``` + +You might want to turn off Boost `-DHIGHFIVE_USE_BOOST=Off` or turn on other +optional dependencies. + +## Contributing +There's numerous HDF5 features that haven't been wrapped yet. HighFive is a +collaborative effort to slowly cover ever larger parts of the HDF5 library. +The process of contributing is to fork the repository and then create a PR. +Please ensure that any new API is appropriately documented and covered with +tests. + +### Code formatting +The project is formatted using clang-format version 12.0.1 and CI will complain +if a commit isn't formatted accordingly. The `.clang-format` is at the root of +the git repository. Conveniently, `clang-format` is available via `pip`: + +```bash +python -m venv venv +source venv/bin/activate + +pip install clang-format==12.0.1 +``` + +The changed lines can be formatted with `git-clang-format`, e.g. to format all lines changed compared to master: + +```bash +git-clang-format master +``` +(add `-f` to allow formatting unstaged changes if you trust it to not destroy +your changes.) + +## Releasing HighFive +Before releasing a new version perform the following: + +* Update `CHANGELOG.md` and `AUTHORS.txt` as required. +* Update `CMakeLists.txt` and `include/highfive/H5Version.hpp`. +* Follow semantic versioning when deciding the next version number. +* Check that + [HighFive-testing](https://github.com/BlueBrain/HighFive-testing/actions) ran + recently. + +At this point there should be a commit on master which will be the release +candidate. Don't tag it yet. + +Next step is to update the [HighFive/spack](https://github.com/BlueBrain/spack) +recipe such that the proposed version points to the release candidate using the +SHA of that commit. The recipe will look something like this: + +```python + # ... + + version("2.8.0", commit="094400f22145bcdcd2726ce72888d9d1c21e7068") + version("2.7.1", sha256="25b4c51a94d1e670dc93b9b73f51e79b65d8ff49bcd6e5d5582d5ecd2789a249") + version("2.7.0", sha256="8e05672ddf81a59ce014b1d065bd9a8c5034dbd91a5c2578e805ef880afa5907") + # ... +``` + +Push the changes to the BlueBrain spack repository. This will trigger building +all BBP dependencies of HighFive, i.e. another integration test. Don't actually +merge this commit yet. + +Now that we know that the integration test ran, and all BBP software can be +built with the proposed version of HighFive, we can proceed and create the +release. Once this is done perform a final round of updates: + +* Download the archive (`*.tar.gz`) and compute its SHA256. +* Update BlueBrain Spack recipe to use the archive and not the Git commit. +* Update the upstream Spack recipe. + diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/doxygen-awesome-css/doxygen-awesome.css b/modules/drivers/highfive/HighFive-2.8.0/doc/doxygen-awesome-css/doxygen-awesome.css similarity index 99% rename from modules/drivers/highfive/HighFive-2.7.1/doc/doxygen-awesome-css/doxygen-awesome.css rename to modules/drivers/highfive/HighFive-2.8.0/doc/doxygen-awesome-css/doxygen-awesome.css index e8399cbce..08238977a 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/doxygen-awesome-css/doxygen-awesome.css +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/doxygen-awesome-css/doxygen-awesome.css @@ -776,6 +776,8 @@ html.dark-mode iframe#MSearchResults { #side-nav { padding: 0 !important; background: var(--side-nav-background); + min-width: 8px; + max-width: 50vw; } @media screen and (max-width: 767px) { @@ -863,8 +865,9 @@ html.dark-mode iframe#MSearchResults { } .ui-resizable-e { - background: var(--separator-color); - width: 1px; + width: 4px; + background: transparent; + box-shadow: inset -1px 0 0 0 var(--separator-color); } /* @@ -2450,6 +2453,10 @@ h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a. Optional tab feature */ +.tabbed { + margin: var(--spacing-medium) auto; +} + .tabbed ul { padding-inline-start: 0px; margin: 0; @@ -2487,6 +2494,7 @@ h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a. font-size: var(--page-font-size); cursor: pointer; box-shadow: 0 1px 0 0 var(--separator-color); + position: relative; } .tabs-overview button.tab-button .tab-title { @@ -2501,22 +2509,22 @@ h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a. } .tabs-overview button.tab-button:hover .tab-title { - background: var(--primary-color); - color: var(--page-background-color); + background: var(--separator-color); box-shadow: none; } .tabs-overview button.tab-button.active { color: var(--primary-color); - box-shadow: 0 1px 0 0 var(--primary-color), inset 0 -1px 0 0 var(--primary-color); } -@media (prefers-color-scheme: dark) { - html:not(.light-mode) .tabs-overview button.tab-button:hover .tab-title { - color: var(--page-foreground-color); - } +.tabs-overview button.tab-button.active::after { + content: ''; + display: block; + position: absolute; + left: 0px; + bottom: 0; + right: 0px; + height: 3px; + border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; + background-color: var(--primary-color); } - -html.dark-mode .tabs-overview button.tab-button:hover .tab-title { - color: var(--page-foreground-color); -} \ No newline at end of file diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/doxygen-awesome-css/update_doxygen_awesome.sh b/modules/drivers/highfive/HighFive-2.8.0/doc/doxygen-awesome-css/update_doxygen_awesome.sh similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/doxygen-awesome-css/update_doxygen_awesome.sh rename to modules/drivers/highfive/HighFive-2.8.0/doc/doxygen-awesome-css/update_doxygen_awesome.sh diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/environment.yaml b/modules/drivers/highfive/HighFive-2.8.0/doc/environment.yaml similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/environment.yaml rename to modules/drivers/highfive/HighFive-2.8.0/doc/environment.yaml diff --git a/modules/drivers/highfive/HighFive-2.8.0/doc/installation.md b/modules/drivers/highfive/HighFive-2.8.0/doc/installation.md new file mode 100644 index 000000000..41521bba5 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/installation.md @@ -0,0 +1,254 @@ +# Beginners Installation Guide on Linux + +These installation instruction are aimed at developers that aren't very +familiar with installing C/C++ software and using CMake on Linux. + +## Obtaining CMake +You'll need a compiler and CMake. We'll assume that a reasonably modern C++ +compiler is available. Often a sufficiently new version CMake is also present +on the system. + +If not, there's two options: use the system package manager or use `pip`. CMake +is improving in leaps and bounds. Which means you want a recent version. We +suggest reconsidering fighting an older version of CMake if you can simply +install the newest version via `pip`. + +## Obtaining HDF5 +First, you need to decide if you need MPI-support. Rule of thumb is: if you're +unsure, then you don't need it. If you need MPI you must install an +MPI-enabled version of HDF5. Otherwise pick either one, if something is already +installed, e.g. because `h5py` was installed as a system package, stick with +that version. + +The options for installing HDF5 are: +1. Use the system package manager. +2. On a cluster use modules. +3. Use [Spack](https://github.com/spack/spack). +4. Use [Conan](https://conan.io). +5. Manually install it. + +The system package manager will install HDF5 in a default location, were CMake +will later be able to find it without further help. All the other approaches +install into a non-default location and CMake might need help locating HDF5. +The way one tells CMake where to find HDF5 is through `CMAKE_PREFIX_PATH`, +e.g., + + cmake -DCMAKE_PREFIX_PATH="${HDF5_ROOT}" ... + +Note that `${HDF5_ROOT}` points to the folder which contains the two folders +`include` and `lib`. + +### System Package Manager +The default choice is to use the system package manager to install HDF5. +One thing to keep an eye out is that certain Linux distributions don't install +the headers automatically. Since you're about to develop an application which +(indirectly) uses HDF5, you need those headers. If the packages are split, the +development package is often suffixed with `-dev` or `-devel`. + +#### Ubuntu +The package manager is apt. To install the HDF5 C library without MPI support: + + sudo apt-get install libhdf5-dev + +for MPI support you'd install `libhdf5-openmpi-dev`. + +#### ArchLinux +On ArchLinux you install + + sudo pacman -S hdf5 + +or `hdf5-openmpi` for HDF5 with OpenMPI support. + + +### Using Modules +If you're on a cluster, HDF5 has almost certainly been installed for you. +Figure out how to use it. This is the preferred solution on clusters. As +always, the precise instructions depend on the cluster, but something like + + module load hdf5 + +will probably be part of the solution. Try if `module avail` helps. Otherwise, +you'd need to check the documentation for your cluster. Cluster admins like to +hide the good stuff, i.e. modern versions, behind another package `"new"` or +some other mechanism. + +You might need to know where HDF5 has been installed. You can find out what a +module does by typing + + module show hdf5 + +If it contains something about prepending to `CMAKE_PREFIX_PATH`, then CMake +should find the correct version automatically after loading the module. + +### Using Spack +If neither of the above work, the next best choice might be Spack. It's a +package manager for scientific computing. The general idea behind it is to +avoid dependency issues by compiling a compatible set of everything. + +Obtain Spack by cloning their repo: + + git clone https://github.com/spack/spack.git + +Activate Spack by sourcing a magic file: + + source spack/share/spack/setup-env.sh + +which will put the command `spack` into your `PATH`. Okay, now we're set. First +step is to create an environment for your project, which we'll call `useful`: + + spack env create useful + spack env activate -p useful + spack add hdf5 + spack install --jobs NPROC + +If you need MPI support use `hdf5+mpi` instead. The location of the HDF5 +installation is `spack location --install-dir hdf5`. + +### Conan +If Spack doesn't work, you can try Conan. + +### Manually Install HDF5 +If all else fails, you can try to manually install HDF5. First you need to +obtain the source code. For example by using `git` or by downloading an archive +from their webpage. + + git clone https://github.com/HDFGroup/hdf5 + cd hdf5 + git checkout hdf5-1_14_0 + +Now, fingers crossed it'll compile and install: + + cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=../hdf5-v1.14.0 -B build . + cmake --build build --parallel [NPROC] + cmake --install build + +Note that here we picked the installation path (or more precisely prefix) to be +`../hdf5-v1.14.0`. You might want to install HDF5 somewhere else. This +installation prefix is the also the path you need to give CMake so it's able to +find HDF5 later on. + +### Confirming HDF5 Has Been Installed +For this purpose we need a dummy file `dummy.cpp` to compile: + + #include + + int main() { + auto file = H5Fcreate("foo.h5", H5F_ACC_EXCL, H5P_DEFAULT, H5P_DEFAULT); + H5Fclose(file); + return 0; + } + +and a `CMakeLists.txt` with the following contents + + cmake_minimum_required(VERSION 3.19) + project(Dummy) + + find_package(HDF5 REQUIRED) + add_executable(dummy dummy.cpp) + target_link_libraries(dummy HDF5::HDF5) + +Now run CMake to configure the build system and keep an eye out for some a line +related to HDF5, e.g. + + $ cmake -B build . + ... + -- Found HDF5: hdf5-shared (found version "1.14.0") + ... + +Compile and check that it's doing something with sensible + + $ cmake -build build --verbose + [ 50%] Building CXX object CMakeFiles/dummy.dir/dummy.cpp.o + /usr/bin/c++ ... -isystem ${HDF5_ROOT}/include ... -c ${PWD}/dummy.cpp + [100%] Linking CXX executable dummy + /usr/bin/c++ ... -o dummy -Wl,-rpath,${HDF5_ROOT}/lib ${HDF5_ROOT}/lib/libhdf5.so.310.0.0 ... + +mostly you're checking that the paths are what you'd expect them to be. If +this command was successful, chances are high that HDF5 is properly installed +and you've figured out the correct CMake invocations. If you want you can run +the executable: + + build/dummy + +which would create an empty file `foo.h5`. + +## Obtaining HighFive + +In principle the same instruction as for HDF5 can be used. However, HighFive is +much less popular compared to HDF5 and therefore the system package manager +likely doesn't know about it, nor does Conan. You're left with Spack and the +manual process. It seems someone has done the wonderful work of adding HighFive +to conda-forge, so maybe that's also an option. + +### Git Submodules +This is the well-tested method for "vendoring" HighFive, i.e. including the +HighFive sources with those of you project. + +### Spack +Similarly as for HDF5, you can use Spack to install HighFive: + + spack env activate -p useful + spack add highfive + spack install --jobs NPROC + +Again `spack location --install-dir highfive` will return the path where +HighFive was installed. Since the Spack recipe of HighFive declares HDF5 as a +dependency, technically, it's not necessary to add `hdf5`, just `highfive` is +enough. + +### Manually Install HighFive +Just like before the steps are, clone, configure, compile (kinda a no-op), +install. The detailed instructions would be + + git clone --recursive https://github.com/BlueBrain/HighFive.git + cd HighFive + git checkout v2.8.0 + +If it complains that Catch is missing, you forgot the `--recursive`. To fix +this you type + + git submodule update --init --recursive + +Okay, on to configure, compile and install. The CMake commands are + + cmake -DCMAKE_INSTALL_PREFIX=../highfive-v2.7.1 -DHIGHFIVE_USE_BOOST=Off -B build . + cmake --build build --parallel + cmake --install build + +### Confirming It Works +We again need a dummy file called `dummy.cpp` with the following contents + + #include + + int main() { + auto file = HighFive::File("foo.h5", HighFive::File::Create); + return 0; + } + +and the following `CMakeLists.txt`: + + cmake_minimum_required(VERSION 3.19) + project(UseHighFive) + + find_package(HighFive REQUIRED) + add_executable(dummy dummy.cpp) + target_link_libraries(dummy HighFive) + +The required CMake commands are: + + $ cmake -DCMAKE_PREFIX_PATH="${HDF5_ROOT};${HIGHFIVE_ROOT}" -B build . + ... + -- HIGHFIVE 2.7.1: (Re)Detecting Highfive dependencies (HIGHFIVE_USE_INSTALL_DEPS=NO) + -- Found HDF5: hdf5-shared (found version "1.14.0") + ... + + $ cmake --build build --verbose + [ 50%] Building CXX object CMakeFiles/dummy.dir/dummy.cpp.o + /usr/bin/c++ ... -isystem ${HIGHFIVE_ROOT}/include -isystem ${HDF5_ROOT}/include ... -c dummy.cpp + [100%] Linking CXX executable dummy + /usr/bin/c++ ... -o dummy -Wl,-rpath,${HDF5_ROOT}/lib ${HDF5_ROOT}/lib/libhdf5.so.310.0.0 ... + +Pay attention to the semi-colon (not colon like the rest of Linux) used to +separate directories in `CMAKE_PREFIX_PATH`. If this worked you should be set +to either copy the instruction to your "real" project, or start developing the +rest of your project. diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example1_hdf5.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example1_hdf5.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example1_hdf5.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example1_hdf5.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example1_highfive.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example1_highfive.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example1_highfive.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example1_highfive.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example3.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example3.cpp similarity index 95% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example3.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example3.cpp index 64f2ed6be..e18fbbf83 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example3.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example3.cpp @@ -1,4 +1,4 @@ -#include +#include typedef struct { diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example6.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example6.cpp similarity index 93% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example6.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example6.cpp index 8f7419f23..41a050570 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example6.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example6.cpp @@ -2,9 +2,7 @@ #include -#include -#include -#include +#include int main(int argc, char** argv) { diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost.cpp similarity index 85% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost.cpp index aceaa2068..56b78d074 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost.cpp @@ -1,11 +1,9 @@ #include #define H5_USE_BOOST 1 +#include #include -#include -#include -#include using complex_t = std::complex; diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost_ublas.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost_ublas.cpp similarity index 97% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost_ublas.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost_ublas.cpp index 3a2b4c73a..986a671de 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_boost_ublas.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_boost_ublas.cpp @@ -1,6 +1,7 @@ #include #define H5_USE_BOOST 1 +#include // In some versions of Boost (starting with 1.64), you have to // include the serialization header before ublas @@ -8,7 +9,6 @@ #include #include -#include using namespace HighFive; diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_easy_h5py.py b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_easy_h5py.py similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_easy_h5py.py rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_easy_h5py.py diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_easy_highfive.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_easy_highfive.cpp similarity index 99% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_easy_highfive.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_easy_highfive.cpp index 07d37a22c..700056cae 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_easy_highfive.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_easy_highfive.cpp @@ -1,4 +1,5 @@ #include + #include int main() { diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_props.cpp b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_props.cpp similarity index 94% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_props.cpp rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_props.cpp index e46fe119c..0e5b14bde 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/example_props.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/example_props.cpp @@ -1,4 +1,4 @@ -#include +#include using namespace HighFive; diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/examples.js b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/examples.js similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/examples.js rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/examples.js diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/godbolt.org.ico b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/godbolt.org.ico similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/godbolt.org.ico rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/godbolt.org.ico diff --git a/modules/drivers/highfive/HighFive-2.7.1/doc/poster/index.html b/modules/drivers/highfive/HighFive-2.8.0/doc/poster/index.html similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/doc/poster/index.html rename to modules/drivers/highfive/HighFive-2.8.0/doc/poster/index.html diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Attribute.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Attribute.hpp new file mode 100644 index 000000000..810d388ae --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Attribute.hpp @@ -0,0 +1,266 @@ +/* + * Copyright (c), 2017, Ali Can Demiralp + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#pragma once + +#include + +#include + +#include "H5DataType.hpp" +#include "H5Object.hpp" +#include "bits/H5Friends.hpp" +#include "bits/H5Path_traits.hpp" + +namespace HighFive { +class DataSpace; + +namespace detail { + +/// \brief Internal hack to create an `Attribute` from an ID. +/// +/// WARNING: Creating an Attribute from an ID has implications w.r.t. the lifetime of the object +/// that got passed via its ID. Using this method careless opens up the suite of issues +/// related to C-style resource management, including the analog of double free, dangling +/// pointers, etc. +/// +/// NOTE: This is not part of the API and only serves to work around a compiler issue in GCC which +/// prevents us from using `friend`s instead. This function should only be used for internal +/// purposes. The problematic construct is: +/// +/// template +/// friend class SomeCRTP; +/// +/// \private +Attribute make_attribute(hid_t hid); +} // namespace detail + +/// \brief Class representing an Attribute of a DataSet or Group +/// +/// \sa AnnotateTraits::createAttribute, AnnotateTraits::getAttribute, AnnotateTraits::listAttributeNames, AnnotateTraits::hasAttribute, AnnotateTraits::deleteAttribute for create, get, list, check or delete Attribute +class Attribute: public Object, public PathTraits { + public: + const static ObjectType type = ObjectType::Attribute; + + /// \brief Get the name of the current Attribute. + /// \code{.cpp} + /// auto attr = dset.createAttribute("my_attribute", DataSpace::From(string_list)); + /// std::cout << attr.getName() << std::endl; // Will print "my_attribute" + /// \endcode + /// \since 2.2.2 + std::string getName() const; + + /// \brief The number of bytes required to store the attribute in the HDF5 file. + /// \code{.cpp} + /// size_t size = dset.createAttribute("foo", DataSpace(1, 2)).getStorageSize(); + /// \endcode + /// \since 1.0 + size_t getStorageSize() const; + + /// \brief Get the DataType of the Attribute. + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); + /// auto dtype = attr.getDataType(); // Will be an hdf5 type deduced from int + /// \endcode + /// \since 1.0 + DataType getDataType() const; + + /// \brief Get the DataSpace of the current Attribute. + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); + /// auto dspace = attr.getSpace(); // This will be a DataSpace of dimension 1 * 2 + /// \endcode + /// \since 1.0 + DataSpace getSpace() const; + + /// \brief Get the DataSpace of the current Attribute. + /// \note This is an alias of getSpace(). + /// \since 1.0 + DataSpace getMemSpace() const; + + /// \brief Get the value of the Attribute. + /// \code{.cpp} + /// Attribute attr = dset.getAttribute("foo"); + /// // The value will contains what have been written in the attribute + /// std::vector value = attr.read>(); + /// \endcode + /// \since 2.5.0 + template + T read() const; + + /// \brief Get the value of the Attribute in a buffer. + /// + /// Read the attribute into an existing object. Only available for + /// supported types `T`. If `array` has preallocated the correct amount of + /// memory, then this routine should not trigger reallocation. Otherwise, + /// if supported, the object will be resized. + /// + /// An exception is raised if the numbers of dimension of the buffer and of + /// the attribute are different. + /// + /// \code{.cpp} + /// // Will read into `value` avoiding memory allocation if the dimensions + /// // match, i.e. if the attribute `"foo"` has three element. + /// std::vector value(3); + /// file.getAttribute("foo").read(value); + /// \endcode + /// \since 1.0 + template + void read(T& array) const; + + /// \brief Read the attribute into a pre-allocated buffer. + /// \param array A pointer to the first byte of sufficient pre-allocated memory. + /// \param mem_datatype The DataType of the array. + /// + /// \note This is the shallowest wrapper around `H5Aread`. If possible + /// prefer either Attribute::read() const or Attribute::read(T&) const. + /// + /// \code{.cpp} + /// auto attr = file.getAttribute("foo"); + /// + /// // Simulate custom allocation by the application. + /// size_t n_elements = attr.getSpace().getElementCount(); + /// int * ptr = (int*) malloc(n_elements*sizeof(int)); + /// + /// // Read into the pre-allocated memory. + /// attr.read(ptr, mem_datatype); + /// \endcode + /// \since 2.2.2 + template + void read(T* array, const DataType& mem_datatype) const; + + /// \brief Read the attribute into a buffer. + /// Behaves like Attribute::read(T*, const DataType&) const but + /// additionally this overload deduces the memory datatype from `T`. + /// + /// \param array Pointer to the first byte of pre-allocated memory. + /// + /// \note If possible prefer either Attribute::read() const or Attribute::read(T&) const. + /// + /// \code{.cpp} + /// auto attr = file.getAttribute("foo"); + /// + /// // Simulate custom allocation by the application. + /// size_t n_elements = attr.getSpace().getElementCount(); + /// int * ptr = (int*) malloc(n_elements*sizeof(int)); + /// + /// // Read into the pre-allocated memory. + /// attr.read(ptr); + /// \endcode + /// \since 2.2.2 + template + void read(T* array) const; + + /// \brief Write the value into the Attribute. + /// + /// Write the value to the attribute. For supported types `T`, this overload + /// will write the value to the attribute. The datatype and dataspace are + /// deduced automatically. However, since the attribute has already been + /// created, the dimensions of `value` must match those of the attribute. + /// + /// \code{.cpp} + /// // Prefer the fused version if creating and writing the attribute + /// // at the same time. + /// dset.createAttribute("foo", std::vector{1, 2, 3}); + /// + /// // To overwrite the value: + /// std::vector value{4, 5, 6}; + /// dset.getAttribute("foo").write(value); + /// \endcode + /// \since 1.0 + template + void write(const T& value); + + /// \brief Write from a raw pointer. + /// + /// Values that have been correctly arranged memory, can be written directly + /// by passing a raw pointer. + /// + /// \param buffer Pointer to the first byte of the value. + /// \param mem_datatype The DataType of the buffer. + /// + /// \note This is the shallowest wrapper around `H5Awrite`. It's useful + /// if you need full control. If possible prefer Attribute::write. + /// + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(2, 3)); + /// + /// // Simulate the application creating `value` and only exposing access + /// // to the raw pointer `ptr`. + /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; + /// int * ptr = (int*) value.data(); + /// + /// // Simply write the bytes to disk. + /// attr.write(ptr, AtomicType()); + /// \endcode + /// \since 2.2.2 + template + void write_raw(const T* buffer, const DataType& mem_datatype); + + /// \brief Write from a raw pointer. + /// + /// Much like Attribute::write_raw(const T*, const DataType&). + /// Additionally, this overload attempts to automatically deduce the + /// datatype of the buffer. Note, that the file datatype is already set. + /// + /// \param buffer Pointer to the first byte. + /// + /// \note If possible prefer Attribute::write. + /// + /// \code{.cpp} + /// // Simulate the application creating `value` and only exposing access + /// // to the raw pointer `ptr`. + /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; + /// int * ptr = (int*) value.data(); + /// + /// // Simply write the bytes to disk. + /// attr.write(ptr); + /// \endcode + /// \since 2.2.2 + template + void write_raw(const T* buffer); + + /// \brief The create property list used for this attribute. + /// + /// Some of HDF5 properties/setting of an attribute are defined by a + /// create property list. This method returns a copy of the create + /// property list used during creation of the attribute. + /// + /// \code{.cpp} + /// auto acpl = attr.getCreatePropertyList(); + /// + /// // For example to create another attribute with the same properties. + /// file.createAttribute("foo", 42, acpl); + /// \endcode + /// \since 2.5.0 + AttributeCreateProps getCreatePropertyList() const { + return details::get_plist(*this, H5Aget_create_plist); + } + + // No empty attributes + Attribute() = delete; + + protected: + using Object::Object; + + private: +#if HIGHFIVE_HAS_FRIEND_DECLARATIONS + template + friend class ::HighFive::AnnotateTraits; +#endif + + friend Attribute detail::make_attribute(hid_t); +}; + +namespace detail { +inline Attribute make_attribute(hid_t hid) { + return Attribute(hid); +} +} // namespace detail + +} // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataSet.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataSet.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataSet.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataSet.hpp diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataSpace.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataSpace.hpp new file mode 100644 index 000000000..95d04dbbb --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataSpace.hpp @@ -0,0 +1,243 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#pragma once + +#include +#include +#include +#include +#include + +#include "H5Object.hpp" +#include "bits/H5_definitions.hpp" + +namespace HighFive { + +/// \brief Class representing the space (dimensions) of a DataSet +/// +/// \code{.cpp} +/// // Create a DataSpace of dimension 1 x 2 x 3 +/// DataSpace dspace(1, 2, 3); +/// std::cout << dspace.getElementCount() << std::endl; // Print 1 * 2 * 3 = 6 +/// std::cout << dspace.getNumberDimensions() << std::endl; // Print 3 +/// std::vector dims = dspace.getDimensions(); // dims is {1, 2, 3} +/// \endcode +class DataSpace: public Object { + public: + const static ObjectType type = ObjectType::DataSpace; + + /// \brief Magic value to specify that a DataSpace can grow without limit. + /// + /// This value should be used with DataSpace::DataSpace(const std::vector& dims, const + /// std::vector& maxdims); + /// + /// \since 2.0 + static const size_t UNLIMITED = SIZE_MAX; + + /// \brief An enum to create scalar and null DataSpace with DataSpace::DataSpace(DataspaceType dtype). + /// + /// This enum is needed otherwise we will not be able to distringuish between both with normal + /// constructors. Both have a dimension of 0. + /// \since 1.3 + enum DataspaceType { + dataspace_scalar, ///< Value to create scalar DataSpace + dataspace_null, ///< Value to create null DataSpace + // simple dataspace are handle directly from their dimensions + }; + + /// \brief Create a DataSpace of N-dimensions from a std::vector. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(std::vector{1, 3}); + /// \endcode + /// \since 1.0 + explicit DataSpace(const std::vector& dims); + + /// \brief Create a DataSpace of N-dimensions from a std::array. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(std::array{1, 3}); + /// \endcode + /// \since 2.3 + template + explicit DataSpace(const std::array& dims); + + /// \brief Create a DataSpace of N-dimensions from an initializer list. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace{1, 3}; + /// \endcode + /// \since 2.1 + DataSpace(const std::initializer_list& dims); + + /// \brief Create a DataSpace of N-dimensions from direct values. + /// \param dim1 The first dimension + /// \param dims The following dimensions + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(1, 3); + /// \endcode + /// \since 2.1 + template + explicit DataSpace(size_t dim1, Args... dims); + + /// \brief Create a DataSpace from a pair of iterators. + /// \param begin The beginning of the container + /// \param end The end of the container + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// std::vector v{1, 3}; + /// DataSpace(v.begin(), v.end()); + /// \endcode + /// + /// \since 2.0 + // Attention: Explicitly disable DataSpace(int_like, int_like) from trying + // to use this constructor + template ::value, IT>::type> + DataSpace(const IT begin, const IT end); + + /// \brief Create a resizable N-dimensional DataSpace. + /// \param dims Initial size of dataspace + /// \param maxdims Maximum size of the dataspace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3. + /// // It can later be resized up to a maximum of 10 x 10 + /// DataSpace(std::vector{1, 3}, std::vector{10, 10}); + /// \endcode + /// + /// \see UNLIMITED for a DataSpace that can be resized without limit. + /// \since 2.0 + explicit DataSpace(const std::vector& dims, const std::vector& maxdims); + + /// \brief Create a scalar or a null DataSpace. + /// + /// This overload enables creating scalar or null data spaces, both have + /// dimension 0. + /// + /// \param space_type The value from the enum + /// + /// \code{.cpp} + /// DataSpace(DataspaceType::dataspace_scalar); + /// \endcode + /// + /// \attention Avoid braced intialization in these cases, i.e. + /// \code{.cpp} + /// // This is not a scalar dataset: + /// DataSpace{DataspaceType::dataspace_scalar}; + /// \endcode + /// + /// \since 1.3 + explicit DataSpace(DataspaceType space_type); + + /// \brief Create a copy of the DataSpace which will have different id. + /// + /// \code{.cpp} + /// DataSpace dspace1(1, 3); + /// auto dspace2 = dspace.clone(); + /// \endcode + /// + /// \since 1.0 + DataSpace clone() const; + + /// \brief Returns the number of dimensions of a DataSpace. + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// size_t number_of_dim = dspace.getNumberDimensions(); // returns 2 + /// \endcode + /// \since 1.0 + size_t getNumberDimensions() const; + + /// \brief Returns the size of the dataset in each dimension. + /// + /// For zero-dimensional datasets (e.g. scalar or null datasets) an empty + /// vector is returned. + /// + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// auto dims = dspace.getDimensions(); // returns {1, 3} + /// \endcode + /// + /// \sa DataSpace::getMaxDimensions + /// + /// \since 1.0 + std::vector getDimensions() const; + + /// \brief Return the number of elements in this DataSpace. + /// + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// size_t elementcount = dspace.getElementCount(); // return 1 x 3 = 3 + /// \endcode + /// \since 2.1 + size_t getElementCount() const; + + /// \brief Returns the maximum size of the dataset in each dimension. + /// + /// This is the maximum size a dataset can be extended to, which may be + /// different from the current size of the dataset. + /// + /// \code{.cpp} + /// DataSpace dspace(std::vector{1, 3}, std::vector{UNLIMITED, 10}); + /// dspace.getMaxDimensions(); // Return {UNLIMITED, 10} + /// \endcode + /// + /// \sa DataSpace::getDimensions + /// \since 2.0 + std::vector getMaxDimensions() const; + + /// \brief Automatically deduce the DataSpace from a container/value. + /// + /// Certain containers and scalar values are fully supported by HighFive. + /// For these containers, HighFive can deduce the dimensions from `value`. + /// + /// \code{.cpp} + /// double d = 42.0; + /// std::vector> v = {{4, 5, 6}, {7, 8, 9}}; + /// DataSpace::From(v); // A DataSpace of dimensions 2, 3. + /// DataSpace::From(d); // A scalar dataspace. + /// \endcode + /// + /// \since 1.0 + template + static DataSpace From(const T& value); + + /// \brief Create a DataSpace from a value of type string array. + /// \param string_array An C-array of C-string (null-terminated). + /// + /// \code{.cpp} + /// char string_array[2][10] = {"123456789", "abcdefghi"}; + /// auto dspace = DataSpace::FromCharArrayStrings(string_array); // dspace is a DataSpace of + /// dimensions 2 + /// \endcode + /// \since 2.2 + template + static DataSpace FromCharArrayStrings(const char (&string_array)[N][Width]); + + protected: + DataSpace() = default; + + friend class Attribute; + friend class File; + friend class DataSet; +}; + +} // namespace HighFive + +// We include bits right away since DataSpace is user-constructible +#include "bits/H5Dataspace_misc.hpp" diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataType.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataType.hpp similarity index 80% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataType.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataType.hpp index 43f758e45..886107961 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5DataType.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5DataType.hpp @@ -11,9 +11,12 @@ #include #include +#include + #include "H5Object.hpp" #include "bits/H5Utils.hpp" +#include "bits/string_padding.hpp" #include "H5PropertyList.hpp" namespace HighFive { @@ -47,6 +50,7 @@ inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } +class StringType; /// /// \brief HDF5 Data Type @@ -85,6 +89,11 @@ class DataType: public Object { /// bool isFixedLenStr() const; + /// + /// \brief Returns this datatype as a `StringType`. + /// + StringType asStringType() const; + /// /// \brief Check the DataType was default constructed. /// Such value might represent auto-detection of the datatype from a buffer @@ -106,8 +115,67 @@ class DataType: public Object { friend class File; friend class DataSet; friend class CompoundType; + template + friend class NodeTraits; +}; + + +enum class CharacterSet : std::underlying_type::type { + Ascii = H5T_CSET_ASCII, + Utf8 = H5T_CSET_UTF8, +}; + +class StringType: public DataType { + public: + /// + /// \brief For stings return the character set. + /// + CharacterSet getCharacterSet() const; + + /// + /// \brief For fixed length stings return the padding. + /// + StringPadding getPadding() const; + + protected: + using DataType::DataType; + friend class DataType; +}; + +class FixedLengthStringType: public StringType { + public: + /// + /// \brief Create a fixed length string datatype. + /// + /// The string will be `size` bytes long, regardless whether it's ASCII or + /// UTF8. In particular, a string with `n` UFT8 characters in general + /// requires `4*n` bytes. + /// + /// The string padding is subtle, essentially it's just a hint. A + /// nullterminated string is guaranteed to have one `'\0'` which marks the + /// semantic end of the string. The length of the buffer must be at least + /// `size` bytes regardless. HDF5 will read or write `size` bytes, + /// irrespective of the when the `\0` occurs. + /// + /// Note that when writing passing `StringPadding::NullTerminated` is a + /// guarantee to the reader that it contains a `\0`. Therefore, make sure + /// that the string really is nullterminated. Otherwise prefer a + /// null-padded string which only means states that the buffer is filled up + /// with 0 or more `\0`. + FixedLengthStringType(size_t size, + StringPadding padding, + CharacterSet character_set = CharacterSet::Ascii); }; +class VariableLengthStringType: public StringType { + public: + /// + /// \brief Create a variable length string HDF5 datatype. + /// + VariableLengthStringType(CharacterSet character_set = CharacterSet::Ascii); +}; + + /// /// \brief create an HDF5 DataType from a C++ type /// @@ -175,11 +243,14 @@ class CompoundType: public DataType { size_t n_members = static_cast(result); members.reserve(n_members); for (unsigned i = 0; i < n_members; i++) { - const char* name = H5Tget_member_name(_hid, i); + char* name = H5Tget_member_name(_hid, i); size_t offset = H5Tget_member_offset(_hid, i); hid_t member_hid = H5Tget_member_type(_hid, i); DataType member_type{member_hid}; - members.emplace_back(name, member_type, offset); + members.emplace_back(std::string(name), member_type, offset); + if (H5free_memory(name) < 0) { + throw DataTypeException("Could not free names from the compound datatype"); + } } } @@ -250,7 +321,7 @@ class EnumType: public DataType { } EnumType(std::initializer_list t_members) - : EnumType(std::vector({t_members})) {} + : EnumType(std::vector(t_members)) {} /// \brief Commit datatype into the given Object /// \param object Location to commit object into @@ -280,15 +351,20 @@ DataType create_and_check_datatype(); /// Although fixed-len arrays can be created 'raw' without the need for /// this structure, to retrieve results efficiently it must be used. /// +/// \tparam N Size of the string in bytes, including the null character. Note, +/// that all string must be null-terminated. +/// template class FixedLenStringArray { public: FixedLenStringArray() = default; /// - /// \brief Create a FixedStringArray from a raw contiguous buffer + /// \brief Create a FixedStringArray from a raw contiguous buffer. + /// + /// The argument `n_strings` specifies the number of strings. /// - FixedLenStringArray(const char array[][N], std::size_t length); + FixedLenStringArray(const char array[][N], std::size_t n_strings); /// /// \brief Create a FixedStringArray from a sequence of strings. diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Easy.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Easy.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Easy.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Easy.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Exception.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Exception.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Exception.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Exception.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5File.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5File.hpp similarity index 88% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5File.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5File.hpp index d8dac1696..9b393e5a3 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5File.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5File.hpp @@ -110,6 +110,17 @@ class File: public Object, public NodeTraits, public AnnotateTraits return details::get_plist(*this, H5Fget_access_plist); } + /// \brief Get the size of this file in bytes + size_t getFileSize() const; + + /// \brief Get the amount of tracked, unused space in bytes. + /// + /// Note, this is a wrapper for `H5Fget_freespace` and returns the number + /// bytes in the free space manager. This might be different from the total + /// amount of unused space in the HDF5 file, since the free space manager + /// might not track everything or not track across open-close cycles. + size_t getFreeSpace() const; + protected: File() = default; using Object::Object; diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5FileDriver.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5FileDriver.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5FileDriver.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5FileDriver.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Group.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Group.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Group.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Group.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Object.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Object.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Object.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Object.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5PropertyList.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5PropertyList.hpp similarity index 77% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5PropertyList.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5PropertyList.hpp index 6122820e5..53b3c4a13 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5PropertyList.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5PropertyList.hpp @@ -22,6 +22,67 @@ namespace HighFive { +/// \defgroup PropertyLists Property Lists +/// HDF5 is configured through what they call property lists. In HDF5 the +/// process has four steps: +/// +/// 1. Create a property list. As users we now have an `hid_t` identifying the +/// property list. +/// 2. Set properties as desired. +/// 3. Pass the HID to the HDF5 function to be configured. +/// 4. Free the property list. +/// +/// Note that the mental picture is that one creates a settings object, and +/// then passes those settings to a function such as `H5Dwrite`. In and of +/// themselves the settings don't change the behaviour of HDF5. Rather they +/// need to be used to take affect. +/// +/// The second aspect is that property lists represent any number of related +/// settings, e.g. there's property lists anything related to creating files +/// and another for accessing files, same for creating and accessing datasets, +/// etc. Settings that affect creating files, must be passed a file creation +/// property list, while settings that affect file access require a file access +/// property list. +/// +/// In HighFive the `PropertyList` works similar in that it's a object +/// representing the settings, i.e. internally it's just the property lists +/// HID. Just like in HDF5 one adds the settings to the settings object; and +/// then passes the settings object to the respective method. Example: +/// +/// +/// // Create an object which contains the setting to +/// // open files with MPI-IO. +/// auto fapl = FileAccessProps(); +/// fapl.add(MPIOFileAccess(MPI_COMM_WORLD, MPI_INFO_NULL); +/// +/// // To open a specific file with MPI-IO, we do: +/// auto file = File("foo.h5", File::ReadOnly, fapl); +/// +/// Note that the `MPIOFileAccess` object by itself doesn't affect the +/// `FileAccessProps`. Rather it needs to be explicitly added to the `fapl` +/// (the group of file access related settings), and then the `fapl` needs to +/// be passed to the constructor of `File` for the settings to take affect. +/// +/// This is important to understand when reading properties. Example: +/// +/// // Obtain the file access property list: +/// auto fapl = file.getAccessPropertyList() +/// +/// // Extracts a copy of the collective MPI-IO metadata settings from +/// // the group of file access related setting, i.e. the `fapl`: +/// auto mpio_metadata = MPIOCollectiveMetadata(fapl); +/// +/// if(mpio_metadata.isCollectiveRead()) { +/// // something specific if meta data is read collectively. +/// } +/// +/// // Careful, this only affects the `mpio_metadata` object, but not the +/// // `fapl`, and also not whether `file` uses collective MPI-IO for +/// // metadata. +/// mpio_metadata = MPIOCollectiveMetadata(false, false); +/// +/// @{ + /// /// \brief Types of property lists /// @@ -72,6 +133,26 @@ class PropertyListBase: public Object { friend T details::get_plist(const U&, hid_t (*f)(hid_t)); }; +/// \interface PropertyInterface +/// \brief HDF5 file property object +/// +/// A property is an object which is expected to have a method with the +/// following signature `void apply(hid_t hid) const` +/// +/// \sa Instructions to document C++20 concepts with Doxygen: https://github.com/doxygen/doxygen/issues/2732#issuecomment-509629967 +/// +/// \cond +#if HIGHFIVE_HAS_CONCEPTS && __cplusplus >= 202002L +template +concept PropertyInterface = requires(P p, const hid_t hid) { + {p.apply(hid)}; +}; + +#else +#define PropertyInterface typename +#endif +/// \endcond + /// /// \brief HDF5 property Lists /// @@ -88,8 +169,8 @@ class PropertyList: public PropertyListBase { /// Add a property to this property list. /// A property is an object which is expected to have a method with the /// following signature void apply(hid_t hid) const - /// - template + /// \tparam PropertyInterface + template void add(const P& property); /// @@ -377,6 +458,7 @@ class PageBufferSize { #endif /// \brief Set hints as to how many links to expect and their average length +/// \implements PropertyInterface /// class EstimatedLinkInfo { public: @@ -402,6 +484,7 @@ class EstimatedLinkInfo { }; +/// \implements PropertyInterface class Chunking { public: explicit Chunking(const std::vector& dims); @@ -420,6 +503,7 @@ class Chunking { std::vector _dims; }; +/// \implements PropertyInterface class Deflate { public: explicit Deflate(unsigned level); @@ -431,6 +515,7 @@ class Deflate { const unsigned _level; }; +/// \implements PropertyInterface class Szip { public: explicit Szip(unsigned options_mask = H5_SZIP_EC_OPTION_MASK, @@ -446,6 +531,7 @@ class Szip { const unsigned _pixels_per_block; }; +/// \implements PropertyInterface class Shuffle { public: Shuffle() = default; @@ -460,6 +546,7 @@ class Shuffle { /// The precise time of when HDF5 requests space to store the dataset /// can be configured. Please, consider the upstream documentation for /// `H5Pset_alloc_time`. +/// \implements PropertyInterface class AllocationTime { public: explicit AllocationTime(H5D_alloc_time_t alloc_time); @@ -476,6 +563,7 @@ class AllocationTime { /// Dataset access property to control chunk cache configuration. /// Do not confuse with the similar file access property for H5Pset_cache +/// \implements PropertyInterface class Caching { public: /// https://support.hdfgroup.org/HDF5/doc/RM/H5P/H5Pset_chunk_cache.html for @@ -498,6 +586,7 @@ class Caching { double _w0; }; +/// \implements PropertyInterface class CreateIntermediateGroup { public: explicit CreateIntermediateGroup(bool create = true); @@ -518,6 +607,7 @@ class CreateIntermediateGroup { }; #ifdef H5_HAVE_PARALLEL +/// \implements PropertyInterface class UseCollectiveIO { public: explicit UseCollectiveIO(bool enable = true); @@ -540,6 +630,7 @@ class UseCollectiveIO { /// creation of this object. This object will not update automatically for later data transfers, /// i.e. `H5Pget_mpio_no_collective_cause` is called in the constructor, and not when fetching /// a value, such as `wasCollective`. +/// \implements PropertyInterface class MpioNoCollectiveCause { public: explicit MpioNoCollectiveCause(const DataTransferProps& dxpl); @@ -575,6 +666,7 @@ struct CreationOrder { /// /// Let user retrieve objects by creation order time instead of name. /// +/// \implements PropertyInterface class LinkCreationOrder { public: /// @@ -599,6 +691,44 @@ class LinkCreationOrder { unsigned _flags; }; + +/// +/// \brief Set threshold for attribute storage. +/// +/// HDF5 can store Attributes in the object header (compact) or in the B-tree +/// (dense). This property sets the threshold when attributes are moved to one +/// or the other storage format. +/// +/// Please refer to the upstream documentation of `H5Pset_attr_phase_change` or +/// Section 8 (Attributes) in the User Guide, in particular Subsection 8.5. +/// +/// \implements PropertyInterface +class AttributePhaseChange { + public: + /// + /// \brief Create the property from the threshold values. + /// + /// When the number of attributes hits `max_compact` the attributes are + /// moved to dense storage, once the number drops to below `min_dense` the + /// attributes are moved to compact storage. + AttributePhaseChange(unsigned max_compact, unsigned min_dense); + + /// \brief Extract threshold values from property list. + explicit AttributePhaseChange(const GroupCreateProps& gcpl); + + unsigned max_compact() const; + unsigned min_dense() const; + + private: + friend GroupCreateProps; + void apply(hid_t hid) const; + + unsigned _max_compact; + unsigned _min_dense; +}; + +/// @} + } // namespace HighFive #include "bits/H5PropertyList_misc.hpp" diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Reference.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Reference.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Reference.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Reference.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Selection.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Selection.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Selection.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Selection.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Utility.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Utility.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Utility.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Utility.hpp diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Version.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Version.hpp new file mode 100644 index 000000000..dc238432c --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Version.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c), 2020 + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#pragma once + +#define HIGHFIVE_VERSION_MAJOR 2 +#define HIGHFIVE_VERSION_MINOR 8 +#define HIGHFIVE_VERSION_PATCH 0 + +/** \brief Concatenated representation of the HighFive version. + * + * \warning The macro `HIGHFIVE_VERSION` by itself isn't valid C/C++. + * + * However, it can be stringified with two layers of macros, e.g., + * \code{.cpp} + * #define STRINGIFY_VALUE(s) STRINGIFY_NAME(s) + * #define STRINGIFY_NAME(s) #s + * + * std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n"; + * \endcode + */ +#define HIGHFIVE_VERSION 2.8.0 + +/** \brief String representation of the HighFive version. + * + * \warning This macro only exists from 2.7.1 onwards. + */ +#define HIGHFIVE_VERSION_STRING "2.8.0" diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Version.hpp.in b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Version.hpp.in similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/H5Version.hpp.in rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/H5Version.hpp.in diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Annotate_traits.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Annotate_traits.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Annotate_traits.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Annotate_traits.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Annotate_traits_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Annotate_traits_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Annotate_traits_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Annotate_traits_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Attribute_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Attribute_misc.hpp similarity index 80% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Attribute_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Attribute_misc.hpp index 65cdb2d86..651678829 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Attribute_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Attribute_misc.hpp @@ -61,8 +61,9 @@ inline T Attribute::read() const { template inline void Attribute::read(T& array) const { const DataSpace& mem_space = getMemSpace(); + auto file_datatype = getDataType(); const details::BufferInfo buffer_info( - getDataType(), + file_datatype, [this]() -> std::string { return this->getName(); }, details::BufferInfo::read); @@ -82,37 +83,43 @@ inline void Attribute::read(T& array) const { return; } - auto r = details::data_converter::get_reader(dims, array); - read(r.get_pointer(), buffer_info.data_type); + auto r = details::data_converter::get_reader(dims, array, file_datatype); + read(r.getPointer(), buffer_info.data_type); // re-arrange results - r.unserialize(); - auto t = create_datatype::base_type>(); + r.unserialize(array); + + auto t = buffer_info.data_type; auto c = t.getClass(); + if (c == DataTypeClass::VarLen || t.isVariableStr()) { #if H5_VERSION_GE(1, 12, 0) // This one have been created in 1.12.0 - (void) H5Treclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.get_pointer()); + (void) H5Treclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer()); #else // This one is deprecated since 1.12.0 - (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.get_pointer()); + (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer()); #endif } } template -inline void Attribute::read(T* array, const DataType& dtype) const { +inline void Attribute::read(T* array, const DataType& mem_datatype) const { static_assert(!std::is_const::value, "read() requires a non-const structure to read data into"); - using element_type = typename details::inspector::base_type; - // Auto-detect mem datatype if not provided - const DataType& mem_datatype = dtype.empty() ? create_and_check_datatype() - : dtype; if (H5Aread(getId(), mem_datatype.getId(), static_cast(array)) < 0) { HDF5ErrMapper::ToException("Error during HDF5 Read: "); } } +template +inline void Attribute::read(T* array) const { + using element_type = typename details::inspector::base_type; + const DataType& mem_datatype = create_and_check_datatype(); + + read(array, mem_datatype); +} + template inline void Attribute::write(const T& buffer) { const DataSpace& mem_space = getMemSpace(); @@ -121,8 +128,10 @@ inline void Attribute::write(const T& buffer) { return; } + auto file_datatype = getDataType(); + const details::BufferInfo buffer_info( - getDataType(), + file_datatype, [this]() -> std::string { return this->getName(); }, details::BufferInfo::write); @@ -132,18 +141,23 @@ inline void Attribute::write(const T& buffer) { << " into dataset of dimensions " << mem_space.getNumberDimensions(); throw DataSpaceException(ss.str()); } - auto w = details::data_converter::serialize(buffer); - write_raw(w.get_pointer(), buffer_info.data_type); + auto w = details::data_converter::serialize(buffer, file_datatype); + write_raw(w.getPointer(), buffer_info.data_type); } template -inline void Attribute::write_raw(const T* buffer, const DataType& dtype) { - using element_type = typename details::inspector::base_type; - const auto& mem_datatype = dtype.empty() ? create_and_check_datatype() : dtype; - +inline void Attribute::write_raw(const T* buffer, const DataType& mem_datatype) { if (H5Awrite(getId(), mem_datatype.getId(), buffer) < 0) { HDF5ErrMapper::ToException("Error during HDF5 Write: "); } } +template +inline void Attribute::write_raw(const T* buffer) { + using element_type = typename details::inspector::base_type; + const auto& mem_datatype = create_and_check_datatype(); + + write_raw(buffer, mem_datatype); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Converter_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Converter_misc.hpp new file mode 100644 index 000000000..00749d1b6 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Converter_misc.hpp @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2022 Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#pragma once + +#include + +#include "H5Inspector_misc.hpp" +#include "../H5DataType.hpp" + +namespace HighFive { +namespace details { + +template +struct is_std_string { + static constexpr bool value = + std::is_same::base_type, std::string>::value; +}; + +template +struct enable_shallow_copy + : public std::enable_if::value && inspector::is_trivially_copyable, V> {}; + +template +struct enable_deep_copy + : public std::enable_if::value && !inspector::is_trivially_copyable, V> {}; + +template +struct enable_string_copy: public std::enable_if::value, V> {}; + + +template +struct ShallowCopyBuffer { + using type = unqualified_t; + using hdf5_type = + typename std::conditional::hdf5_type>::type, + typename inspector::hdf5_type>::type; + + ShallowCopyBuffer() = delete; + + explicit ShallowCopyBuffer(typename std::conditional::type val) + : ptr(inspector::data(val)){}; + + hdf5_type* getPointer() const { + return ptr; + } + + hdf5_type* begin() const { + return getPointer(); + } + + void unserialize(T& /* val */) const { + /* nothing to do. */ + } + + private: + hdf5_type* ptr; +}; + +template +struct DeepCopyBuffer { + using type = unqualified_t; + using hdf5_type = typename inspector::hdf5_type; + + explicit DeepCopyBuffer(const std::vector& _dims) + : buffer(inspector::getSize(_dims)) + , dims(_dims) {} + + hdf5_type* getPointer() { + return buffer.data(); + } + + hdf5_type const* getPointer() const { + return buffer.data(); + } + + hdf5_type* begin() { + return getPointer(); + } + + hdf5_type const* begin() const { + return getPointer(); + } + + void unserialize(T& val) const { + inspector::unserialize(buffer.data(), dims, val); + } + + private: + std::vector buffer; + std::vector dims; +}; + +enum class BufferMode { Read, Write }; + + +/// +/// \brief String length in bytes excluding the `\0`. +/// +inline size_t char_buffer_size(char const* const str, size_t max_string_length) { + for (size_t i = 0; i <= max_string_length; ++i) { + if (str[i] == '\0') { + return i; + } + } + + return max_string_length; +} + + +/// +/// \brief A buffer for reading/writing strings. +/// +/// A string in HDF5 can be represented as a fixed or variable length string. +/// The important difference for this buffer is that `H5D{read,write}` expects +/// different input depending on whether the strings are fixed or variable length. +/// For fixed length strings, it expects an array of chars, i.e. one string +/// packed after the other contiguously. While for variable length strings it +/// expects a list of pointers to the beginning of each string. Variable length +/// string must be null-terminated; because that's how their length is +/// determined. +/// +/// This buffer hides the difference between fixed and variable length strings +/// by having internal data structures available for both cases at compile time. +/// The choice which internal buffer to use is made at runtime. +/// +/// Consider an HDF5 dataset with N fixed-length strings, each of which is M +/// characters long. Then the in-memory strings are copied into an internal +/// buffer of size N*M. If null- or space-padded the buffer should be filled +/// with the appropriate character. This is important if the in-memory strings +/// are less than M characters long. +/// +/// An HDF5 dataset with N variable-length strings (all null-terminated) uses +/// the internal list of pointers to the beginning of each string. Those +/// pointers can either point to the in-memory strings themselves, if those +/// strings are known to be null-terminated. Otherwise the in-memory strings are +/// copied to an internal buffer of null-terminated strings; and the pointer +/// points to the start of the string in the internal buffer. +/// +/// This class is responsible for arranging the strings properly before passing +/// the buffers to HDF5. To keep this class generic, it provides a generic +/// read/write interface to the internal strings, i.e. a pointer with a size. +/// For reading from the buffer the proxy is called `StringConstView`. This +/// proxy object is to be used by the `inspector` to copy from the buffer into +/// the final destination, e.g. an `std::string`. Similarly, there's a proxy +/// object for serializing into the buffer, i.e. the `StringView`. Again the +/// `inspector` is responsible for obtaining the pointer, size and padding of +/// the string. +/// +/// Nomenclature: +/// - size of a string is the number of bytes required to store the string, +/// including the null character for null-terminated strings. +/// +/// - length of a string is the number of bytes without the null character. +/// +/// Note: both 'length' and 'size' are counted in number of bytes, not number +/// of symbols or characters. Even for UTF8 strings. +template +struct StringBuffer { + using type = unqualified_t; + using hdf5_type = typename inspector::hdf5_type; + + class StringView { + public: + StringView(StringBuffer& _buffer, size_t _i) + : buffer(_buffer) + , i(_i) {} + + /// + /// \brief Assign the in-memory string to the buffer. + /// + /// This method copies the in-memory string to the appropriate + /// internal buffer as needed. + /// + /// The `length` is the length of the string in bytes. + void assign(char const* data, size_t length, StringPadding padding) { + if (buffer.isVariableLengthString()) { + if (padding == StringPadding::NullTerminated) { + buffer.variable_length_pointers[i] = data; + } else { + buffer.variable_length_buffer[i] = std::string(data, length); + buffer.variable_length_pointers[i] = buffer.variable_length_buffer[i].data(); + } + } else if (buffer.isFixedLengthString()) { + // If the buffer is fixed-length and null-terminated, then + // `buffer.string_length` doesn't include the null-character. + if (length > buffer.string_length) { + throw std::invalid_argument("String length too big."); + } + + memcpy(&buffer.fixed_length_buffer[i * buffer.string_size], data, length); + } + } + + private: + StringBuffer& buffer; + size_t i; + }; + + + class StringConstView { + public: + StringConstView(const StringBuffer& _buffer, size_t _i) + : buffer(_buffer) + , i(_i) {} + + /// \brief Pointer to the first byte of the string. + /// + /// The valid indices for this pointer are: 0, ..., length() - 1. + char const* data() const { + if (buffer.isVariableLengthString()) { + return buffer.variable_length_pointers[i]; + } else { + return &buffer.fixed_length_buffer[i * buffer.string_size]; + } + } + + /// \brief Length of the string in bytes. + /// + /// Note that for null-terminated strings the "length" doesn't include + /// the null character. Hence, if storing this string as a + /// null-terminated string, the destination buffer needs to be at least + /// `length() + 1` bytes long. + size_t length() const { + if (buffer.isNullTerminated()) { + return char_buffer_size(data(), buffer.string_length); + } else { + return buffer.string_length; + } + } + + private: + const StringBuffer& buffer; + size_t i; + }; + + + class Iterator { + public: + Iterator(StringBuffer& _buffer, size_t _pos) + : buffer(_buffer) + , pos(_pos) {} + + Iterator operator+(size_t n_strings) const { + return Iterator(buffer, pos + n_strings); + } + + void operator+=(size_t n_strings) { + pos += n_strings; + } + + StringView operator*() { + return StringView(buffer, pos); + } + + StringConstView operator*() const { + return StringConstView(buffer, pos); + } + + private: + StringBuffer& buffer; + size_t pos; + }; + + StringBuffer(std::vector _dims, const DataType& _file_datatype) + : file_datatype(_file_datatype.asStringType()) + , padding(file_datatype.getPadding()) + , string_size(file_datatype.isVariableStr() ? size_t(-1) : file_datatype.getSize()) + , string_length(string_size - size_t(isNullTerminated())) + , dims(_dims) { + if (string_size == 0 && isNullTerminated()) { + throw DataTypeException( + "Fixed-length, null-terminated need at least one byte to store the " + "null-character."); + } + + auto n_strings = compute_total_size(dims); + if (isVariableLengthString()) { + variable_length_buffer.resize(n_strings); + variable_length_pointers.resize(n_strings); + } else { + char pad = padding == StringPadding::SpacePadded ? ' ' : '\0'; + fixed_length_buffer.assign(n_strings * string_size, pad); + } + } + + bool isVariableLengthString() const { + return file_datatype.isVariableStr(); + } + + bool isFixedLengthString() const { + return file_datatype.isFixedLenStr(); + } + + bool isNullTerminated() const { + return file_datatype.getPadding() == StringPadding::NullTerminated; + } + + + void* getPointer() { + if (file_datatype.isVariableStr()) { + return variable_length_pointers.data(); + } else { + return fixed_length_buffer.data(); + } + } + + Iterator begin() { + return Iterator(*this, 0ul); + } + + void unserialize(T& val) { + inspector::unserialize(begin(), dims, val); + } + + private: + StringType file_datatype; + StringPadding padding; + size_t string_size; // Size of buffer required to store the string. + // Meaningful for fixed length strings only. + size_t string_length; // Semantic length of string. + std::vector dims; + + std::vector fixed_length_buffer; + std::vector variable_length_buffer; + std::vector< + typename std::conditional::type*> + variable_length_pointers; +}; + + +template +struct Writer; + +template +struct Writer::type>: public ShallowCopyBuffer { + private: + using super = ShallowCopyBuffer; + + public: + explicit Writer(const T& val, const DataType& /* file_datatype */) + : super(val){}; +}; + +template +struct Writer::type>: public DeepCopyBuffer { + explicit Writer(const T& val, const DataType& /* file_datatype */) + : DeepCopyBuffer(inspector::getDimensions(val)) { + inspector::serialize(val, this->begin()); + } +}; + +template +struct Writer::type>: public StringBuffer { + explicit Writer(const T& val, const DataType& _file_datatype) + : StringBuffer(inspector::getDimensions(val), _file_datatype) { + inspector::serialize(val, this->begin()); + } +}; + +template +struct Reader; + +template +struct Reader::type>: public ShallowCopyBuffer { + private: + using super = ShallowCopyBuffer; + using type = typename super::type; + + public: + Reader(const std::vector&, type& val, const DataType& /* file_datatype */) + : super(val) {} +}; + +template +struct Reader::type>: public DeepCopyBuffer { + private: + using super = DeepCopyBuffer; + using type = typename super::type; + + public: + Reader(const std::vector& _dims, type&, const DataType& /* file_datatype */) + : super(_dims) {} +}; + + +template +struct Reader::type>: public StringBuffer { + public: + explicit Reader(const std::vector& _dims, + const T& /* val */, + const DataType& _file_datatype) + : StringBuffer(_dims, _file_datatype) {} +}; + +struct data_converter { + template + static Writer serialize(const typename inspector::type& val, + const DataType& file_datatype) { + return Writer(val, file_datatype); + } + + template + static Reader get_reader(const std::vector& dims, + T& val, + const DataType& file_datatype) { + // TODO Use bufferinfo for recursive_ndim + auto effective_dims = details::squeezeDimensions(dims, inspector::recursive_ndim); + inspector::prepare(val, effective_dims); + return Reader(effective_dims, val, file_datatype); + } +}; + +} // namespace details +} // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5DataSet_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5DataSet_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5DataSet_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5DataSet_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5DataType_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5DataType_misc.hpp similarity index 76% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5DataType_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5DataType_misc.hpp index afe200c80..8535d617a 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5DataType_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5DataType_misc.hpp @@ -22,10 +22,68 @@ #include #endif -#include "H5Converter_misc.hpp" +#include "H5Inspector_misc.hpp" namespace HighFive { +namespace detail { + +inline hid_t h5t_copy(hid_t original) { + auto copy = H5Tcopy(original); + if (copy == H5I_INVALID_HID) { + HDF5ErrMapper::ToException("Error copying datatype."); + } + + return copy; +} + +inline hsize_t h5t_get_size(hid_t hid) { + hsize_t size = H5Tget_size(hid); + if (size == 0) { + HDF5ErrMapper::ToException("Error getting size of datatype."); + } + + return size; +} + +inline H5T_cset_t h5t_get_cset(hid_t hid) { + auto cset = H5Tget_cset(hid); + if (cset == H5T_CSET_ERROR) { + HDF5ErrMapper::ToException("Error getting cset of datatype."); + } + + return cset; +} + +inline H5T_str_t h5t_get_strpad(hid_t hid) { + auto strpad = H5Tget_strpad(hid); + if (strpad == H5T_STR_ERROR) { + HDF5ErrMapper::ToException("Error getting strpad of datatype."); + } + + return strpad; +} + +inline void h5t_set_size(hid_t hid, hsize_t size) { + if (H5Tset_size(hid, size) < 0) { + HDF5ErrMapper::ToException("Error setting size of datatype."); + } +} + +inline void h5t_set_cset(hid_t hid, H5T_cset_t cset) { + if (H5Tset_cset(hid, cset) < 0) { + HDF5ErrMapper::ToException("Error setting cset of datatype."); + } +} + +inline void h5t_set_strpad(hid_t hid, H5T_str_t strpad) { + if (H5Tset_strpad(hid, strpad) < 0) { + HDF5ErrMapper::ToException("Error setting strpad of datatype."); + } +} +} // namespace detail + + namespace { // unnamed inline DataTypeClass convert_type_class(const H5T_class_t& tclass); inline std::string type_class_string(DataTypeClass); @@ -41,7 +99,7 @@ inline DataTypeClass DataType::getClass() const { } inline size_t DataType::getSize() const { - return H5Tget_size(_hid); + return detail::h5t_get_size(_hid); } inline bool DataType::operator==(const DataType& other) const { @@ -68,68 +126,110 @@ inline bool DataType::isReference() const { return H5Tequal(_hid, H5T_STD_REF_OBJ) > 0; } +inline StringType DataType::asStringType() const { + if (getClass() != DataTypeClass::String) { + throw DataTypeException("Invalid conversion to StringType."); + } + + if (isValid() && H5Iinc_ref(_hid) < 0) { + throw ObjectException("Reference counter increase failure"); + } + + return StringType(_hid); +} + inline std::string DataType::string() const { return type_class_string(getClass()) + std::to_string(getSize() * 8); } +inline StringPadding StringType::getPadding() const { + return StringPadding(detail::h5t_get_strpad(_hid)); +} + +inline CharacterSet StringType::getCharacterSet() const { + return CharacterSet(detail::h5t_get_cset(_hid)); +} + +inline FixedLengthStringType::FixedLengthStringType(size_t size, + StringPadding padding, + CharacterSet character_set) { + if (size == 0 && padding == StringPadding::NullTerminated) { + throw DataTypeException( + "Fixed-length, null-terminated need at least one byte to store the null-character."); + } + + _hid = detail::h5t_copy(H5T_C_S1); + + detail::h5t_set_size(_hid, hsize_t(size)); + detail::h5t_set_cset(_hid, H5T_cset_t(character_set)); + detail::h5t_set_strpad(_hid, H5T_str_t(padding)); +} + +inline VariableLengthStringType::VariableLengthStringType(CharacterSet character_set) { + _hid = detail::h5t_copy(H5T_C_S1); + + detail::h5t_set_size(_hid, H5T_VARIABLE); + detail::h5t_set_cset(_hid, H5T_cset_t(character_set)); +} + // char mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_CHAR); + _hid = detail::h5t_copy(H5T_NATIVE_CHAR); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_SCHAR); + _hid = detail::h5t_copy(H5T_NATIVE_SCHAR); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_UCHAR); + _hid = detail::h5t_copy(H5T_NATIVE_UCHAR); } // short mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_SHORT); + _hid = detail::h5t_copy(H5T_NATIVE_SHORT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_USHORT); + _hid = detail::h5t_copy(H5T_NATIVE_USHORT); } // integer mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_INT); + _hid = detail::h5t_copy(H5T_NATIVE_INT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_UINT); + _hid = detail::h5t_copy(H5T_NATIVE_UINT); } // long mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LONG); + _hid = detail::h5t_copy(H5T_NATIVE_LONG); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_ULONG); + _hid = detail::h5t_copy(H5T_NATIVE_ULONG); } // long long mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LLONG); + _hid = detail::h5t_copy(H5T_NATIVE_LLONG); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_ULLONG); + _hid = detail::h5t_copy(H5T_NATIVE_ULLONG); } // half-float, float, double and long double mapping @@ -138,11 +238,11 @@ using float16_t = half_float::half; template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_FLOAT); + _hid = detail::h5t_copy(H5T_NATIVE_FLOAT); // Sign position, exponent position, exponent size, mantissa position, mantissa size H5Tset_fields(_hid, 15, 10, 5, 0, 10); // Total datatype size (in bytes) - H5Tset_size(_hid, 2); + detail::h5t_set_size(_hid, 2); // Floating point exponent bias H5Tset_ebias(_hid, 15); } @@ -150,17 +250,17 @@ inline AtomicType::AtomicType() { template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_FLOAT); + _hid = detail::h5t_copy(H5T_NATIVE_FLOAT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_DOUBLE); + _hid = detail::h5t_copy(H5T_NATIVE_DOUBLE); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LDOUBLE); + _hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE); } // std string @@ -173,7 +273,7 @@ inline AtomicType::AtomicType() { // std byte template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_B8); + _hid = detail::h5t_copy(H5T_NATIVE_B8); } #endif @@ -200,8 +300,8 @@ class AtomicType>: public DataType { : DataType( CompoundType({{"r", create_datatype(), 0}, {"i", create_datatype(), sizeof(T)}}, sizeof(std::complex))) { - static_assert(std::is_floating_point::value, - "std::complex accepts only floating point numbers."); + static_assert(std::is_arithmetic::value, + "std::complex accepts only floating point and integral numbers."); } }; @@ -230,18 +330,15 @@ inline FixedLenStringArray::FixedLenStringArray(const char array[][N], std::s template inline FixedLenStringArray::FixedLenStringArray(const std::string* iter_begin, const std::string* iter_end) { - datavec.resize(static_cast(iter_end - iter_begin)); - for (auto& dst_array: datavec) { - const char* src = (iter_begin++)->c_str(); - const size_t length = std::min(N - 1, std::strlen(src)); - std::memcpy(dst_array.data(), src, length); - dst_array[length] = 0; + datavec.reserve(static_cast(iter_end - iter_begin)); + for (std::string const* it = iter_begin; it != iter_end; ++it) { + push_back(*it); } } template inline FixedLenStringArray::FixedLenStringArray(const std::vector& vec) - : FixedLenStringArray(&vec.front(), &vec.back()) {} + : FixedLenStringArray(vec.data(), vec.data() + vec.size()) {} template inline FixedLenStringArray::FixedLenStringArray( @@ -271,7 +368,7 @@ inline std::string FixedLenStringArray::getString(std::size_t i) const { // Reference mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_STD_REF_OBJ); + _hid = detail::h5t_copy(H5T_STD_REF_OBJ); } inline size_t find_first_atomic_member_size(hid_t hid) { @@ -294,7 +391,7 @@ inline size_t find_first_atomic_member_size(hid_t hid) { } else if (H5Tget_class(hid) == H5T_STRING) { return 1; } - return H5Tget_size(hid); + return detail::h5t_get_size(hid); } // Calculate the padding required to align an element of a struct @@ -325,7 +422,7 @@ inline void CompoundType::create(size_t size) { // Do a first pass to find the total size of the compound datatype for (auto& member: members) { - size_t member_size = H5Tget_size(member.base_type.getId()); + size_t member_size = detail::h5t_get_size(member.base_type.getId()); if (member_size == 0) { throw DataTypeException("Cannot get size of DataType with hid: " + @@ -393,12 +490,9 @@ inline void EnumType::commit(const Object& object, const std::string& name) c namespace { inline hid_t create_string(size_t length) { - hid_t _hid = H5Tcopy(H5T_C_S1); - if (H5Tset_size(_hid, length) < 0) { - HDF5ErrMapper::ToException("Unable to define datatype size to variable"); - } - // define encoding to UTF-8 by default - H5Tset_cset(_hid, H5T_CSET_UTF8); + hid_t _hid = detail::h5t_copy(H5T_C_S1); + detail::h5t_set_size(_hid, length); + detail::h5t_set_cset(_hid, H5T_CSET_UTF8); return _hid; } diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Dataspace_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Dataspace_misc.hpp similarity index 92% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Dataspace_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Dataspace_misc.hpp index a72054ad2..0fdcacefd 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Dataspace_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Dataspace_misc.hpp @@ -62,9 +62,9 @@ inline DataSpace::DataSpace(const std::vector& dims, const std::vector DataSpace::getDimensions() const { } inline size_t DataSpace::getElementCount() const { - const std::vector& dims = getDimensions(); - return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies()); + hssize_t nelements = H5Sget_simple_extent_npoints(_hid); + if (nelements < 0) { + HDF5ErrMapper::ToException( + "Unable to get number of elements in dataspace"); + } + + return static_cast(nelements); } inline std::vector DataSpace::getMaxDimensions() const { diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Exception_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Exception_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Exception_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Exception_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5FileDriver_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5FileDriver_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5FileDriver_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5FileDriver_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5File_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5File_misc.hpp similarity index 87% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5File_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5File_misc.hpp index a63338b82..b90792a71 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5File_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5File_misc.hpp @@ -127,4 +127,22 @@ inline void File::flush() { } } +inline size_t File::getFileSize() const { + hsize_t sizeValue = 0; + if (H5Fget_filesize(_hid, &sizeValue) < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to retrieve size of file " + getName())); + } + return static_cast(sizeValue); +} + +inline size_t File::getFreeSpace() const { + hssize_t unusedSize = H5Fget_freespace(_hid); + if (unusedSize < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to retrieve unused space of file " + getName())); + } + return static_cast(unusedSize); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Friends.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Friends.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Friends.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Friends.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Converter_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Inspector_misc.hpp similarity index 88% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Converter_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Inspector_misc.hpp index a46f01174..05ed6bc3e 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Converter_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Inspector_misc.hpp @@ -6,13 +6,21 @@ * http://www.boost.org/LICENSE_1_0.txt) * */ + #pragma once #include #include +#include +#include +#include +#include #include #include "../H5Reference.hpp" + +#include "string_padding.hpp" + #ifdef H5_USE_BOOST #include // starting Boost 1.64, serialization header must come before ublas @@ -23,7 +31,9 @@ #include #endif + namespace HighFive { + namespace details { inline bool checkDimensions(const std::vector& dims, size_t n_dim_requested) { @@ -255,14 +265,15 @@ struct inspector: type_helper { throw DataSpaceException("A std::string cannot be written directly."); } - static void serialize(const type& val, hdf5_type* m) { - *m = val.c_str(); + template + static void serialize(const type& val, It m) { + (*m).assign(val.data(), val.size(), StringPadding::NullTerminated); } - static void unserialize(const hdf5_type* vec, - const std::vector& /* dims */, - type& val) { - val = vec[0]; + template + static void unserialize(const It& vec, const std::vector& /* dims */, type& val) { + const auto& view = *vec; + val.assign(view.data(), view.length()); } }; @@ -365,7 +376,10 @@ struct inspector> { sizes[0] = val.size(); if (!val.empty()) { auto s = inspector::getDimensions(val[0]); - std::copy(s.begin(), s.end(), sizes.begin() + 1); + assert(s.size() + ndim == sizes.size()); + for (size_t i = 0; i < s.size(); ++i) { + sizes[i + ndim] = s[i]; + } } return sizes; } @@ -394,7 +408,8 @@ struct inspector> { return inspector::data(val[0]); } - static void serialize(const type& val, hdf5_type* m) { + template + static void serialize(const type& val, It m) { size_t subsize = inspector::getSizeVal(val[0]); for (auto&& e: val) { inspector::serialize(e, m); @@ -402,9 +417,8 @@ struct inspector> { } } - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { + template + static void unserialize(const It& vec_align, const std::vector& dims, type& val) { std::vector next_dims(dims.begin() + 1, dims.end()); size_t next_size = compute_total_size(next_dims); for (size_t i = 0; i < dims[0]; ++i) { @@ -480,6 +494,7 @@ struct inspector> { static constexpr size_t ndim = 1; static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + sizeof(type) == N * sizeof(T) && inspector::is_trivially_copyable; static std::vector getDimensions(const type& val) { @@ -515,7 +530,8 @@ struct inspector> { return inspector::data(val[0]); } - static void serialize(const type& val, hdf5_type* m) { + template + static void serialize(const type& val, It m) { size_t subsize = inspector::getSizeVal(val[0]); for (auto& e: val) { inspector::serialize(e, m); @@ -523,9 +539,8 @@ struct inspector> { } } - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { + template + static void unserialize(const It& vec_align, const std::vector& dims, type& val) { if (dims[0] != N) { std::ostringstream os; os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with " @@ -625,7 +640,18 @@ struct inspector> { static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && inspector::is_trivially_copyable; + + static void assert_not_buggy(Eigen::Index nrows, Eigen::Index ncols) { + if (nrows > 1 && ncols > 1) { + throw std::runtime_error( + "HighFive has been broken for Eigen::Matrix. Please check " + "https://github.com/BlueBrain/HighFive/issues/532."); + } + } + static std::vector getDimensions(const type& val) { + assert_not_buggy(val.rows(), val.cols()); + std::vector sizes{static_cast(val.rows()), static_cast(val.cols())}; auto s = inspector::getDimensions(val.data()[0]); sizes.insert(sizes.end(), s.begin(), s.end()); @@ -646,23 +672,29 @@ struct inspector> { val.resize(static_cast(dims[0]), static_cast(dims[1])); } + + assert_not_buggy(val.rows(), val.cols()); } static hdf5_type* data(type& val) { + assert_not_buggy(val.rows(), val.cols()); return inspector::data(*val.data()); } static const hdf5_type* data(const type& val) { + assert_not_buggy(val.rows(), val.cols()); return inspector::data(*val.data()); } static void serialize(const type& val, hdf5_type* m) { + assert_not_buggy(val.rows(), val.cols()); std::memcpy(m, val.data(), static_cast(val.size()) * sizeof(hdf5_type)); } static void unserialize(const hdf5_type* vec_align, const std::vector& dims, type& val) { + assert_not_buggy(val.rows(), val.cols()); if (dims.size() < 2) { std::ostringstream os; os << "Impossible to pair DataSet with " << dims.size() @@ -733,7 +765,8 @@ struct inspector> { return inspector::data(*val.data()); } - static void serialize(const type& val, hdf5_type* m) { + template + static void serialize(const type& val, It m) { size_t size = val.num_elements(); size_t subsize = inspector::getSizeVal(*val.origin()); for (size_t i = 0; i < size; ++i) { @@ -741,9 +774,8 @@ struct inspector> { } } - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { + template + static void unserialize(It vec_align, const std::vector& dims, type& val) { std::vector next_dims(dims.begin() + ndim, dims.end()); size_t subsize = compute_total_size(next_dims); for (size_t i = 0; i < val.num_elements(); ++i) { @@ -822,88 +854,5 @@ struct inspector> { }; #endif -template -struct Writer { - using hdf5_type = typename inspector::hdf5_type; - const hdf5_type* get_pointer() { - if (vec.empty()) { - return ptr; - } else { - return vec.data(); - } - } - std::vector vec{}; - const hdf5_type* ptr{nullptr}; -}; - -template -struct Reader { - using type = unqualified_t; - using hdf5_type = typename inspector::hdf5_type; - - Reader(const std::vector& _dims, type& _val) - : dims(_dims) - , val(_val) {} - - hdf5_type* get_pointer() { - if (vec.empty()) { - return inspector::data(val); - } else { - return vec.data(); - } - } - - void unserialize() { - if (!vec.empty()) { - inspector::unserialize(vec.data(), dims, val); - } - } - - std::vector dims{}; - std::vector vec{}; - type& val{}; -}; - -struct data_converter { - template - static typename std::enable_if::is_trivially_copyable, Writer>::type serialize( - const typename inspector::type& val) { - Writer w; - w.ptr = inspector::data(val); - return w; - } - - template - static typename std::enable_if::is_trivially_copyable, Writer>::type serialize( - const typename inspector::type& val) { - Writer w; - w.vec.resize(inspector::getSizeVal(val)); - inspector::serialize(val, w.vec.data()); - return w; - } - - template - static - typename std::enable_if>::is_trivially_copyable, Reader>::type - get_reader(const std::vector& dims, T& val) { - auto effective_dims = details::squeezeDimensions(dims, inspector::recursive_ndim); - Reader r(effective_dims, val); - inspector::prepare(r.val, effective_dims); - return r; - } - - template - static typename std::enable_if>::is_trivially_copyable, - Reader>::type - get_reader(const std::vector& dims, T& val) { - auto effective_dims = details::squeezeDimensions(dims, inspector::recursive_ndim); - - Reader r(effective_dims, val); - inspector::prepare(r.val, effective_dims); - r.vec.resize(inspector::getSize(effective_dims)); - return r; - } -}; - } // namespace details } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Iterables_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Iterables_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Iterables_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Iterables_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits.hpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits.hpp index bdd70332e..d53d3f048 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits.hpp @@ -129,6 +129,14 @@ class NodeTraits { /// \return the group object Group getGroup(const std::string& group_name) const; + /// + /// \brief open a commited datatype with the name type_name + /// \param type_name + /// \return the datatype object + DataType getDataType( + const std::string& type_name, + const DataTypeAccessProps& accessProps = DataTypeAccessProps::Default()) const; + /// /// \brief return the number of leaf objects of the node / group /// \return number of leaf objects @@ -208,6 +216,20 @@ class NodeTraits { const LinkAccessProps& linkAccessProps = LinkAccessProps(), const bool parents = true); + /// + /// \brief Creates hardlinks + /// \param link_name The name of the link + /// \param target_obj The target object + /// \param linkCreateProps A Link_Create property list. Notice "parents=true" overrides + /// \param linkAccessProps The Link_Access property list + /// \param parents Whether parent groups should be created: Default: true + template + void createHardLink(const std::string& link_name, + const T& target_obj, + LinkCreateProps linkCreateProps = LinkCreateProps(), + const LinkAccessProps& linkAccessProps = LinkAccessProps(), + const bool parents = true); + private: using derivate_type = Derivate; diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits_misc.hpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits_misc.hpp index 0af128175..2f75ff311 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Node_traits_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Node_traits_misc.hpp @@ -174,6 +174,19 @@ inline Group NodeTraits::getGroup(const std::string& group_name) const return detail::make_group(hid); } +template +inline DataType NodeTraits::getDataType(const std::string& type_name, + const DataTypeAccessProps& accessProps) const { + const auto hid = H5Topen2(static_cast(this)->getId(), + type_name.c_str(), + accessProps.getId()); + if (hid < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to open the datatype \"") + type_name + "\":"); + } + return DataType(hid); +} + template inline size_t NodeTraits::getNumberObjects() const { hsize_t res; @@ -358,6 +371,29 @@ inline void NodeTraits::createExternalLink(const std::string& link_nam } } +template +template +inline void NodeTraits::createHardLink(const std::string& link_name, + const T& target_obj, + LinkCreateProps linkCreateProps, + const LinkAccessProps& linkAccessProps, + const bool parents) { + static_assert(!std::is_same::value, + "hdf5 doesn't support hard links to Attributes"); + if (parents) { + linkCreateProps.add(CreateIntermediateGroup{}); + } + auto status = H5Lcreate_hard(target_obj.getId(), + ".", + static_cast(this)->getId(), + link_name.c_str(), + linkCreateProps.getId(), + linkAccessProps.getId()); + if (status < 0) { + HDF5ErrMapper::ToException(std::string("Unable to create hard link: ")); + } +} + template inline Object NodeTraits::_open(const std::string& node_name, diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Object_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Object_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Object_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Object_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Path_traits.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Path_traits.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Path_traits.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Path_traits.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Path_traits_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Path_traits_misc.hpp similarity index 95% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Path_traits_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Path_traits_misc.hpp index 73704f03a..444e9294b 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Path_traits_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Path_traits_misc.hpp @@ -34,7 +34,7 @@ inline PathTraits::PathTraits() { template inline std::string PathTraits::getPath() const { return details::get_name([this](char* buffer, size_t length) { - return H5Iget_name(static_cast(this)->getId(), buffer, length); + return H5Iget_name(static_cast(*this).getId(), buffer, length); }); } diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5PropertyList_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5PropertyList_misc.hpp similarity index 95% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5PropertyList_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5PropertyList_misc.hpp index 6a4ef9efd..cef301e53 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5PropertyList_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5PropertyList_misc.hpp @@ -70,7 +70,7 @@ inline void PropertyList::_initializeIfNeeded() { } template -template +template inline void PropertyList::add(const P& property) { _initializeIfNeeded(); property.apply(_hid); @@ -543,4 +543,32 @@ inline void LinkCreationOrder::fromPropertyList(hid_t hid) { "Error getting property for link creation order"); } } + +inline AttributePhaseChange::AttributePhaseChange(unsigned max_compact, unsigned min_dense) + : _max_compact(max_compact) + , _min_dense(min_dense) {} + +inline AttributePhaseChange::AttributePhaseChange(const GroupCreateProps& gcpl) { + if (H5Pget_attr_phase_change(gcpl.getId(), &_max_compact, &_min_dense) < 0) { + HDF5ErrMapper::ToException( + "Error getting property for attribute phase change"); + } +} + +inline unsigned AttributePhaseChange::max_compact() const { + return _max_compact; +} + +inline unsigned AttributePhaseChange::min_dense() const { + return _min_dense; +} + +inline void AttributePhaseChange::apply(hid_t hid) const { + if (H5Pset_attr_phase_change(hid, _max_compact, _min_dense) < 0) { + HDF5ErrMapper::ToException( + "Error getting property for attribute phase change"); + } +} + + } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5ReadWrite_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5ReadWrite_misc.hpp similarity index 72% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5ReadWrite_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5ReadWrite_misc.hpp index 491e61389..c8e736174 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5ReadWrite_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5ReadWrite_misc.hpp @@ -19,9 +19,13 @@ template using unqualified_t = typename std::remove_const::type>::type; // Find the type of an eventual char array, otherwise void -template +template struct type_char_array { - using type = void; + using type = typename std::conditional< + std::is_same::base_type, std::string>::value, + std::string, + void>::type; + static constexpr bool is_char_array = false; }; template @@ -29,6 +33,7 @@ struct type_char_array { using type = typename std::conditional, char>::value, char*, typename type_char_array::type>::type; + static constexpr bool is_char_array = true; }; template @@ -36,6 +41,7 @@ struct type_char_array { using type = typename std::conditional, char>::value, char[N], typename type_char_array::type>::type; + static constexpr bool is_char_array = true; }; template @@ -43,7 +49,7 @@ struct BufferInfo { using type_no_const = typename std::remove_const::type; using elem_type = typename details::inspector::base_type; using char_array_t = typename details::type_char_array::type; - static constexpr bool is_char_array = !std::is_same::value; + static constexpr bool is_char_array = details::type_char_array::is_char_array; enum Operation { read, write }; const Operation op; @@ -63,29 +69,44 @@ struct string_type_checker { static DataType getDataType(const DataType&, const DataType&); }; +inline void enforce_ascii_hack(const DataType& dst, const DataType& src) { + // Note: constness only refers to constness of the DataType object, which + // is just an ID, we can/will change properties of `dst`. + + // TEMP. CHANGE: Ensure that the character set is properly configured to prevent + // converter issues on HDF5 <=v1.12.0 when loading ASCII strings first. + // See https://github.com/HDFGroup/hdf5/issues/544 for further information. + if (H5Tget_cset(src.getId()) == H5T_CSET_ASCII) { + H5Tset_cset(dst.getId(), H5T_CSET_ASCII); + } +} + template <> struct string_type_checker { inline static DataType getDataType(const DataType& element_type, const DataType& dtype) { - // TEMP. CHANGE: Ensure that the character set is properly configured to prevent - // converter issues on HDF5 <=v1.12.0 when loading ASCII strings first. - // See https://github.com/HDFGroup/hdf5/issues/544 for further information. - if (H5Tget_class(element_type.getId()) == H5T_STRING && - H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(element_type.getId(), H5T_CSET_ASCII); + if (H5Tget_class(element_type.getId()) == H5T_STRING) { + enforce_ascii_hack(element_type, dtype); } return element_type; } }; +template <> +struct string_type_checker { + inline static DataType getDataType(const DataType&, const DataType& file_datatype) { + // The StringBuffer ensures that the data is transformed such that it + // matches the datatype of the dataset, i.e. `file_datatype` and + // `mem_datatype` are the same. + return file_datatype; + } +}; + template struct string_type_checker { inline static DataType getDataType(const DataType& element_type, const DataType& dtype) { DataType return_type = (dtype.isFixedLenStr()) ? AtomicType() : element_type; - // TEMP. CHANGE: See string_type_checker definition - if (H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(return_type.getId(), H5T_CSET_ASCII); - } + enforce_ascii_hack(return_type, dtype); return return_type; } }; @@ -93,13 +114,11 @@ struct string_type_checker { template <> struct string_type_checker { inline static DataType getDataType(const DataType&, const DataType& dtype) { - if (dtype.isFixedLenStr()) + if (dtype.isFixedLenStr()) { throw DataSetException("Can't output variable-length to fixed-length strings"); - // TEMP. CHANGE: See string_type_checker definition - DataType return_type = AtomicType(); - if (H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(return_type.getId(), H5T_CSET_ASCII); } + DataType return_type = AtomicType(); + enforce_ascii_hack(return_type, dtype); return return_type; } }; @@ -114,11 +133,6 @@ BufferInfo::BufferInfo(const DataType& dtype, F getName, Operation _op) ((is_fixed_len_string && is_char_array) ? 1 : 0)) , data_type( string_type_checker::getDataType(create_datatype(), dtype)) { - if (is_fixed_len_string && std::is_same::value) { - throw DataSetException( - "Can't output std::string as fixed-length. " - "Use raw arrays or FixedLenStringArray"); - } // We warn. In case they are really not convertible an exception will rise on read/write if (dtype.getClass() != data_type.getClass()) { HIGHFIVE_LOG_WARN(getName() + "\": data and hdf5 dataset have different types: " + diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Reference_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Reference_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Reference_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Reference_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Selection_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Selection_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Selection_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Selection_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits.hpp similarity index 85% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits.hpp index 719b4e503..52c52713f 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits.hpp @@ -258,6 +258,15 @@ class SliceTraits { /// Therefore, the only memspaces supported for general hyperslabs are one-dimensional arrays. Selection select(const HyperSlab& hyperslab) const; + /// + /// \brief Select an \p hyperslab in the current Slice/Dataset. + /// + /// If the selection can be read into a simple, multi-dimensional dataspace, + /// then this overload enable specifying the shape of the memory dataspace + /// with `memspace`. Note, that simple implies no offsets, strides or + /// number of blocks, just the size of the block in each dimension. + Selection select(const HyperSlab& hyperslab, const DataSpace& memspace) const; + /// /// \brief Select a region in the current Slice/Dataset of \p count points at /// \p offset separated by \p stride. If strides are not provided they will @@ -308,9 +317,21 @@ class SliceTraits { /// \param xfer_props: Data Transfer properties template void read(T* array, - const DataType& dtype = DataType(), + const DataType& dtype, const DataTransferProps& xfer_props = DataTransferProps()) const; + /// + /// Read the entire dataset into a raw buffer + /// + /// Same as `read(T*, const DataType&, const DataTransferProps&)`. However, + /// this overload deduces the HDF5 datatype of the element of `array` from + /// `T`. Note, that the file datatype is already fixed. + /// + /// \param array: A buffer containing enough space for the data + /// \param xfer_props: Data Transfer properties + template + void read(T* array, const DataTransferProps& xfer_props = DataTransferProps()) const; + /// /// Write the integrality N-dimension buffer to this dataset /// An exception is raised is if the numbers of dimension of the buffer and @@ -322,22 +343,33 @@ class SliceTraits { void write(const T& buffer, const DataTransferProps& xfer_props = DataTransferProps()); /// - /// Write from a raw buffer into this dataset + /// Write from a raw pointer into this dataset. /// /// No dimensionality checks will be performed, it is the user's /// responsibility to ensure that the buffer holds the right amount of /// elements. For n-dimensional matrices the buffer layout follows H5 /// default conventions. + /// + /// Note, this is the shallowest wrapper around `H5Dwrite` and should + /// be used if full control is needed. Generally prefer `write`. + /// /// \param buffer: A buffer containing the data to be written - /// \param dtype: The type of the data, in case it cannot be automatically guessed + /// \param dtype: The datatype of `buffer`, i.e. the memory data type. /// \param xfer_props: The HDF5 data transfer properties, e.g. collective MPI-IO. template void write_raw(const T* buffer, - const DataType& dtype = DataType(), + const DataType& mem_datatype, const DataTransferProps& xfer_props = DataTransferProps()); - protected: - inline Selection select_impl(const HyperSlab& hyperslab, const DataSpace& memspace) const; + /// + /// Write from a raw pointer into this dataset. + /// + /// Same as `write_raw(const T*, const DataTransferProps&)`. However, this + /// overload attempts to guess the data type of `buffer`, i.e. the memory + /// datatype. Note that the file datatype is already fixed. + /// + template + void write_raw(const T* buffer, const DataTransferProps& xfer_props = DataTransferProps()); }; } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits_misc.hpp similarity index 86% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits_misc.hpp index faae237d8..7b07c9abf 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Slice_traits_misc.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Slice_traits_misc.hpp @@ -64,8 +64,8 @@ inline ElementSet::ElementSet(const std::vector>& eleme } template -inline Selection SliceTraits::select_impl(const HyperSlab& hyperslab, - const DataSpace& memspace) const { +inline Selection SliceTraits::select(const HyperSlab& hyperslab, + const DataSpace& memspace) const { // Note: The current limitation are that memspace must describe a // packed memspace. // @@ -98,7 +98,7 @@ inline Selection SliceTraits::select(const std::vector& offset const std::vector& block) const { auto slab = HyperSlab(RegularHyperSlab(offset, count, stride, block)); auto memspace = DataSpace(count); - return select_impl(slab, memspace); + return select(slab, memspace); } template @@ -121,7 +121,7 @@ inline Selection SliceTraits::select(const std::vector& column std::vector memdims = dims; memdims.back() = columns.size(); - return select_impl(slab, DataSpace(memdims)); + return select(slab, DataSpace(memdims)); } template @@ -172,8 +172,10 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ const auto& slice = static_cast(*this); const DataSpace& mem_space = slice.getMemSpace(); + auto file_datatype = slice.getDataType(); + const details::BufferInfo buffer_info( - slice.getDataType(), + file_datatype, [&slice]() -> std::string { return details::get_dataset(slice).getPath(); }, details::BufferInfo::Operation::read); @@ -193,19 +195,20 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ return; } - auto r = details::data_converter::get_reader(dims, array); - read(r.get_pointer(), buffer_info.data_type, xfer_props); + auto r = details::data_converter::get_reader(dims, array, file_datatype); + read(r.getPointer(), buffer_info.data_type, xfer_props); // re-arrange results - r.unserialize(); - auto t = create_datatype::base_type>(); + r.unserialize(array); + + auto t = buffer_info.data_type; auto c = t.getClass(); if (c == DataTypeClass::VarLen || t.isVariableStr()) { #if H5_VERSION_GE(1, 12, 0) // This one have been created in 1.12.0 - (void) H5Treclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.get_pointer()); + (void) H5Treclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer()); #else // This one is deprecated since 1.12.0 - (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.get_pointer()); + (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer()); #endif } } @@ -214,16 +217,12 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ template template inline void SliceTraits::read(T* array, - const DataType& dtype, + const DataType& mem_datatype, const DataTransferProps& xfer_props) const { static_assert(!std::is_const::value, "read() requires a non-const structure to read data into"); - const auto& slice = static_cast(*this); - using element_type = typename details::inspector::base_type; - // Auto-detect mem datatype if not provided - const DataType& mem_datatype = dtype.empty() ? create_and_check_datatype() - : dtype; + const auto& slice = static_cast(*this); if (H5Dread(details::get_dataset(slice).getId(), mem_datatype.getId(), @@ -235,6 +234,15 @@ inline void SliceTraits::read(T* array, } } +template +template +inline void SliceTraits::read(T* array, const DataTransferProps& xfer_props) const { + using element_type = typename details::inspector::base_type; + const DataType& mem_datatype = create_and_check_datatype(); + + read(array, mem_datatype, xfer_props); +} + template template @@ -246,8 +254,10 @@ inline void SliceTraits::write(const T& buffer, const DataTransferProp return; } + auto file_datatype = slice.getDataType(); + const details::BufferInfo buffer_info( - slice.getDataType(), + file_datatype, [&slice]() -> std::string { return details::get_dataset(slice).getPath(); }, details::BufferInfo::Operation::write); @@ -258,19 +268,17 @@ inline void SliceTraits::write(const T& buffer, const DataTransferProp << " into dataset with n = " << buffer_info.n_dimensions << " dimensions."; throw DataSpaceException(ss.str()); } - auto w = details::data_converter::serialize(buffer); - write_raw(w.get_pointer(), buffer_info.data_type, xfer_props); + auto w = details::data_converter::serialize(buffer, file_datatype); + write_raw(w.getPointer(), buffer_info.data_type, xfer_props); } template template inline void SliceTraits::write_raw(const T* buffer, - const DataType& dtype, + const DataType& mem_datatype, const DataTransferProps& xfer_props) { - using element_type = typename details::inspector::base_type; const auto& slice = static_cast(*this); - const auto& mem_datatype = dtype.empty() ? create_and_check_datatype() : dtype; if (H5Dwrite(details::get_dataset(slice).getId(), mem_datatype.getId(), @@ -282,5 +290,14 @@ inline void SliceTraits::write_raw(const T* buffer, } } +template +template +inline void SliceTraits::write_raw(const T* buffer, const DataTransferProps& xfer_props) { + using element_type = typename details::inspector::base_type; + const auto& mem_datatype = create_and_check_datatype(); + + write_raw(buffer, mem_datatype, xfer_props); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Utils.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Utils.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5Utils.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5Utils.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5_definitions.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5_definitions.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/bits/H5_definitions.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/H5_definitions.hpp diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/string_padding.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/string_padding.hpp new file mode 100644 index 000000000..e6e6908dd --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/bits/string_padding.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace HighFive { + +enum class StringPadding : std::underlying_type::type { + NullTerminated = H5T_STR_NULLTERM, + NullPadded = H5T_STR_NULLPAD, + SpacePadded = H5T_STR_SPACEPAD +}; + + +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_Eigen.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_Eigen.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_Eigen.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_Eigen.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_misc.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_misc.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_misc.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_misc.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_opencv.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_opencv.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_opencv.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_opencv.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_public.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_public.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_public.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_public.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_scalar.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_scalar.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_scalar.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_scalar.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_vector.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_vector.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_vector.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_vector.hpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_xtensor.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_xtensor.hpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/include/highfive/h5easy_bits/H5Easy_xtensor.hpp rename to modules/drivers/highfive/HighFive-2.8.0/include/highfive/h5easy_bits/H5Easy_xtensor.hpp diff --git a/modules/drivers/highfive/HighFive-2.8.0/include/highfive/highfive.hpp b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/highfive.hpp new file mode 100644 index 000000000..f5e20cae9 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/include/highfive/highfive.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/README.md b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/README.md similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/README.md rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/README.md diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/hdf5_bench.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/hdf5_bench.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/hdf5_bench.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/hdf5_bench.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/hdf5_bench_improved.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/hdf5_bench_improved.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/hdf5_bench_improved.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/hdf5_bench_improved.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/highfive_bench.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/highfive_bench.cpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/highfive_bench.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/highfive_bench.cpp index e4e04dee8..bcc7be93c 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/highfive_bench.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/highfive_bench.cpp @@ -1,4 +1,4 @@ -#include +#include #include const std::vector> data(1000000, {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}); diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_hdf5_base.png b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_hdf5_base.png similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_hdf5_base.png rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_hdf5_base.png diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_hdf5_improved.png b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_hdf5_improved.png similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_hdf5_improved.png rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_hdf5_improved.png diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_highfive.png b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_highfive.png similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/imgs/bench_highfive.png rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/imgs/bench_highfive.png diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/run_benchmark.sh b/modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/run_benchmark.sh similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/benchmarks/run_benchmark.sh rename to modules/drivers/highfive/HighFive-2.8.0/src/benchmarks/run_benchmark.sh diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/CMakeLists.txt b/modules/drivers/highfive/HighFive-2.8.0/src/examples/CMakeLists.txt similarity index 63% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/CMakeLists.txt rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/CMakeLists.txt index 97196cfa7..8b5f8b0af 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/CMakeLists.txt +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/CMakeLists.txt @@ -1,8 +1,8 @@ -include_directories(${HDF5_INCLUDE_DIRS}) +include(HighFiveWarnings) -function(compile_example exemple_source) +function(compile_example example_source) - get_filename_component(example_filename ${exemple_source} NAME) + get_filename_component(example_filename ${example_source} NAME) string(REPLACE ".cpp" "_bin" example_name ${example_filename}) if(${example_filename} MATCHES ".*eigen.*") @@ -31,15 +31,17 @@ function(compile_example exemple_source) if(${example_name} MATCHES ".*hl_hdf5.*") find_package(HDF5 QUIET COMPONENTS HL NAMES HDF5_HL) - if(${HDF5_FL_FOUND}) - add_executable(${example_name} ${exemple_source}) - target_link_libraries(${example_name} HighFive ${HDF5_HL_LIBRARIES}) + if(${HDF5_HL_FOUND}) + message("HDF5 HL: ${HDF5_HL_LIBRARIES}") + add_executable(${example_name} ${example_source}) + target_link_libraries(${example_name} HighFive HighFiveWarnings ${HDF5_HL_LIBRARIES}) endif() - else() - add_executable(${example_name} ${exemple_source}) - target_link_libraries(${example_name} HighFive) + return() endif() + add_executable(${example_name} ${example_source}) + target_link_libraries(${example_name} HighFive HighFiveWarnings) + endfunction() file(GLOB list_example "*.cpp") diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multi_array_2D.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multi_array_2D.cpp new file mode 100644 index 000000000..4bec1ec12 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multi_array_2D.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include + +#undef H5_USE_BOOST +#define H5_USE_BOOST + +#include +#include + +using namespace HighFive; + +// Create a 2D dataset 10x3 of double with boost multi array +// and write it to a file. +int main(void) { + const int nx = 10; + const int ny = 3; + + boost::multi_array array(boost::extents[nx][ny]); + + for (int i = 0; i < nx; ++i) { + for (int j = 0; j < ny; ++j) { + array[i][j] = double(j + i * ny); + } + } + + // We create a new HDF5 file + File file("boost_multiarray_example.h5", File::Truncate); + + // let's create our dataset of the size of the boost::multi_array + file.createDataSet("dset", array); + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multiarray_complex.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multiarray_complex.cpp similarity index 88% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multiarray_complex.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multiarray_complex.cpp index a5c198583..37481db62 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_multiarray_complex.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_multiarray_complex.cpp @@ -12,10 +12,9 @@ #undef H5_USE_BOOST #define H5_USE_BOOST +#include + #include -#include -#include -#include typedef std::complex complex_t; @@ -25,7 +24,7 @@ int main() { multi_array[1][1][0][0] = complex_t{1.1, 1.2}; HighFive::File file("multi_array_complex.h5", HighFive::File::Truncate); - HighFive::DataSet dataset = file.createDataSet("multi_array", multi_array); + return 0; } diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_ublas_double.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_ublas_double.cpp similarity index 97% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_ublas_double.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_ublas_double.cpp index ca3307ecf..b025475b9 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/boost_ublas_double.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/boost_ublas_double.cpp @@ -11,13 +11,14 @@ #undef H5_USE_BOOST #define H5_USE_BOOST +#include + // In some versions of Boost (starting with 1.64), you have to include the serialization header // before ublas #include #include #include -#include using namespace HighFive; diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/compound_types.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/compound_types.cpp similarity index 73% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/compound_types.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/compound_types.cpp index 0f127f0a6..158bc6dc6 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/compound_types.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/compound_types.cpp @@ -10,7 +10,7 @@ // Compound datatype test :: May 2021 // ////////////////////////////////// -#include +#include typedef struct { @@ -27,17 +27,16 @@ HighFive::CompoundType create_compound_Size2D() { HIGHFIVE_REGISTER_TYPE(Size2D, create_compound_Size2D) int main() { - const std::string FILE_NAME("compounds_test.h5"); - const std::string DATASET_NAME("dims"); + const std::string dataset_name("dims"); - HighFive::File file(FILE_NAME, HighFive::File::Truncate); + HighFive::File file("compounds_test.h5", HighFive::File::Truncate); auto t1 = create_compound_Size2D(); t1.commit(file, "Size2D"); std::vector dims = {{1., 2.5}, {3., 4.5}}; - auto dataset = file.createDataSet(DATASET_NAME, dims); + auto dataset = file.createDataSet(dataset_name, dims); auto g1 = file.createGroup("group1"); - g1.createAttribute(DATASET_NAME, dims); + g1.createAttribute(dataset_name, dims); } diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_attribute_string_integer.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_attribute_string_integer.cpp new file mode 100644 index 000000000..f658457ad --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_attribute_string_integer.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +using namespace HighFive; + +// create a dataset from a vector of string +// read it back and print it +int main(void) { + // Create a new file using the default property lists. + File file("create_attribute.h5", File::Truncate); + + // Create a dummy dataset of one single integer + DataSet dataset = file.createDataSet("dset", DataSpace(1), create_datatype()); + + // Now let's add a attribute on this dataset + // This attribute will be named "note" + // and have the following content + std::string note = "Very important Dataset!"; + + // Write in one line of code: + dataset.createAttribute("note", note); + + // We also add a "version" attribute + // that will be an array 1x2 of integer + std::vector version{1, 0}; + + Attribute v = dataset.createAttribute("version", version); + + // We can also create attributes on the file: + file.createAttribute("file_version", 1); + + // and on groups in the file: + auto group = file.createGroup("group"); + group.createAttribute("secret", 123); + + // let's now list the keys of all attributes + std::vector all_attributes_keys = dataset.listAttributeNames(); + for (const auto& attr: all_attributes_keys) { + std::cout << "attribute: " << attr << std::endl; + } + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_double.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_double.cpp new file mode 100644 index 000000000..d15fbdc54 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_double.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +// Create a dataset name "dset" of double 4x6 +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. Note that + // `File::Truncate` will, if present, truncate the file before opening + // it for reading and writing. + File file("create_dataset_example.h5", File::Truncate); + + // Define the size of our dataset: 2x6 + std::vector dims{2, 6}; + + // Create the dataset + DataSet dataset = file.createDataSet("dset", DataSpace(dims)); + + double data[2][6] = {{1.1, 2.2, 3.3, 4.4, 5.5, 6.6}, + {11.11, 12.12, 13.13, 14.14, 15.15, 16.16}}; + + // write it + dataset.write(data); + + + return 0; // successfully terminated +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_half_float.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_half_float.cpp new file mode 100644 index 000000000..2b720cd18 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_dataset_half_float.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c), 2022, Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#ifdef H5_USE_HALF_FLOAT + +#include +#include +#include + +#include + +const std::string FILE_NAME("create_dataset_half_float_example.h5"); +const std::string DATASET_NAME("dset"); + +// Create a dataset name "dset", size 4x6, and type float16_t (i.e., 16-bit half-precision +// floating-point format) +// +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); + + // Define the size of our dataset: 4x6 + std::vector dims{4, 6}; + + // Create the dataset + DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(dims)); + + std::vector> data; + for (size_t i = 0; i < 4; ++i) { + data.emplace_back(); + for (size_t j = 0; j < 6; ++j) + data[i].emplace_back((i + 1) * (j + 1)); + } + + // write it + dataset.write(data); + + return 0; +} + +#endif diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_datatype.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_datatype.cpp new file mode 100644 index 000000000..0b1a0fb52 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_datatype.cpp @@ -0,0 +1,101 @@ +#include + +#include + +using namespace HighFive; + +static const std::string FILE_NAME("create_datatype_example.h5"); +static const std::string DATASET_NAME("test_dataset"); + + +// Struct representation of custom type (type v below) +typedef struct { + char a; + short b; + unsigned long long c; +} csl; + +bool operator==(csl x, csl y) { + return x.a == y.a && x.b == y.b && x.c == y.c; +} + +bool operator!=(csl x, csl y) { + return !(x == y); +} + +// Tell HighFive how to create the HDF5 datatype for this base type by +// using the HIGHFIVE_REGISTER_TYPE macro +CompoundType create_compound_csl() { + return {{"u1", create_datatype()}, + {"u2", create_datatype()}, + {"u3", create_datatype()}}; +} +HIGHFIVE_REGISTER_TYPE(csl, create_compound_csl) + +int main(void) { + File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); + + // Create a simple compound type with automatic alignment of the + // members. For this the type alignment is trivial. + std::vector t_members( + {{"real", create_datatype()}, {"imag", create_datatype()}}); + CompoundType t(t_members); + t.commit(file, "new_type1"); + + // Create a complex nested datatype with manual alignment + CompoundType u({{"u1", t, 0}, {"u2", t, 9}, {"u3", create_datatype(), 20}}, 26); + u.commit(file, "new_type3"); + + // Create a more complex type with automatic alignment. For this the + // type alignment is more complex. + CompoundType v_aligned{{"u1", create_datatype()}, + {"u2", create_datatype()}, + {"u3", create_datatype()}}; + // introspect the compound type + std::cout << "v_aligned size: " << v_aligned.getSize(); + for (const auto& member: v_aligned.getMembers()) { + std::cout << " field " << member.name << " offset: " << member.offset << std::endl; + } + + v_aligned.commit(file, "new_type2_aligned"); + + // Create a more complex type with a fully packed alignment. The + // equivalent type is created with a standard struct alignment in the + // implementation of HighFive::create_datatype above + CompoundType v_packed({{"u1", create_datatype(), 0}, + {"u2", create_datatype(), 1}, + {"u3", create_datatype(), 3}}, + 11); + v_packed.commit(file, "new_type2_packed"); + + + // Initialise some data + std::vector data; + data.push_back({'f', 1, 4}); + data.push_back({'g', -4, 18}); + + // Write the data into the file in a fully packed form + DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace(2), v_packed); + dataset.write(data); + + file.flush(); + + // Read a subset of the data back + std::vector result; + dataset.select({0}, {2}).read(result); + + for (size_t i = 0; i < data.size(); ++i) { + if (result[i] != data[i]) { + std::cout << "result[" << i << "]:" << std::endl; + std::cout << " " << result[i].a << std::endl; + std::cout << " " << result[i].b << std::endl; + std::cout << " " << result[i].c << std::endl; + std::cout << "data[" << i << "]:" << std::endl; + std::cout << " " << data[i].a << std::endl; + std::cout << " " << data[i].b << std::endl; + std::cout << " " << data[i].c << std::endl; + } + } + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_extensible_dataset.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_extensible_dataset.cpp new file mode 100644 index 000000000..17153cd57 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_extensible_dataset.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +const std::string FILE_NAME("create_extensible_dataset_example.h5"); +const std::string DATASET_NAME("dset"); + +// Create a dataset name "dset" of double 4x6 +// +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); + + // Create a dataspace with initial shape and max shape + DataSpace dataspace = DataSpace({4, 5}, {17, DataSpace::UNLIMITED}); + + // Use chunking + DataSetCreateProps props; + props.add(Chunking(std::vector{2, 2})); + + // Create the dataset + DataSet dataset = file.createDataSet(DATASET_NAME, dataspace, create_datatype(), props); + + // Write into the initial part of the dataset + double t1[3][1] = {{2.0}, {2.0}, {4.0}}; + dataset.select({0, 0}, {3, 1}).write(t1); + + // Resize the dataset to a larger size + dataset.resize({4, 6}); + + // Write into the new part of the dataset + double t2[1][3] = {{4.0, 8.0, 6.0}}; + dataset.select({3, 3}, {1, 3}).write(t2); + + // now we read it back + std::vector> result; + dataset.read(result); + + // we print it out and see: + // 2 0 0 0 0 0 + // 2 0 0 0 0 0 + // 4 0 0 0 0 0 + // 0 0 0 4 8 6 + for (auto row: result) { + for (auto col: row) + std::cout << " " << col; + std::cout << std::endl; + } + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_large_attribute.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_large_attribute.cpp new file mode 100644 index 000000000..022d11d87 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_large_attribute.cpp @@ -0,0 +1,19 @@ +#include +#include + +#include + +int main() { + std::vector large_attr(16000, 0.0); + + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); + HighFive::File file("create_large_attribute.h5", HighFive::File::Truncate, fapl); + auto gcpl = HighFive::GroupCreateProps::Default(); + gcpl.add(HighFive::AttributePhaseChange(0, 0)); + + auto group = file.createGroup("grp", gcpl); + group.createAttribute("attr", large_attr); + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_page_allocated_files.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_page_allocated_files.cpp similarity index 53% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/create_page_allocated_files.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/create_page_allocated_files.cpp index df58f0d3a..0b4d29dff 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/create_page_allocated_files.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/create_page_allocated_files.cpp @@ -12,14 +12,11 @@ #include #include -#include +#include // This example requires HDF5 version 1.10.1 or newer. #if H5_VERSION_GE(1, 10, 1) -const std::string FILE_NAME("create_page_allocated_files.h5"); -const std::string DATASET_NAME("array"); - // This example show how to create an HDF5 file that internally aggregates // metadata and raw data into separate pages. The advantage of this approach // is that reading a single page, pulls in the metadata for a large chunk of @@ -40,34 +37,29 @@ const std::string DATASET_NAME("array"); int main() { using namespace HighFive; - try { - // Create a new file requesting paged allocation. - auto create_props = FileCreateProps{}; - // Let request pagesizes of 16 kB. This setting should be tuned - // in real applications. We'll allow HDF5 to not keep track of - // left-over free space of size less than 128 bytes. Finally, - // we don't need the free space manager to be stored in the - // HDF5 file. - size_t pagesize = 16 * 1024; // Must be tuned. - size_t threshold = 128; - size_t persist = false; + // Create a new file requesting paged allocation. + auto create_props = FileCreateProps{}; - create_props.add(FileSpaceStrategy(H5F_FSPACE_STRATEGY_PAGE, persist, threshold)); - create_props.add(FileSpacePageSize(pagesize)); + // Let request pagesizes of 16 kB. This setting should be tuned + // in real applications. We'll allow HDF5 to not keep track of + // left-over free space of size less than 128 bytes. Finally, + // we don't need the free space manager to be stored in the + // HDF5 file. + size_t pagesize = 16 * 1024; // Must be tuned. + size_t threshold = 128; + size_t persist = false; - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate, create_props); + create_props.add(FileSpaceStrategy(H5F_FSPACE_STRATEGY_PAGE, persist, threshold)); + create_props.add(FileSpacePageSize(pagesize)); - // The `file` (and also the low-level `file.getId()`) behave as normal, i.e. - // one can proceed to add content to the file as usual. + File file("create_page_allocated_files.h5", File::Truncate, create_props); - auto data = std::vector{0.0, 1.0, 2.0}; - file.createDataSet(DATASET_NAME, data); + // The `file` (and also the low-level `file.getId()`) behave as normal, i.e. + // one can proceed to add content to the file as usual. - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } + auto data = std::vector{0.0, 1.0, 2.0}; + file.createDataSet("data", data); return 0; } @@ -77,4 +69,4 @@ int main() { std::cout << "This example can't be run prior to HDF5 1.10.1.\n"; return 0; } -#endif \ No newline at end of file +#endif diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_attribute.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_attribute.cpp similarity index 99% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_attribute.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_attribute.cpp index be03c5378..87a7f6592 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_attribute.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_attribute.cpp @@ -34,6 +34,5 @@ int main() { H5Easy::dumpAttribute(file, "/path/to/measurement", "description", desc); H5Easy::dumpAttribute(file, "/path/to/measurement", "temperature", temperature); - return 0; } diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_dumpoptions.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_dumpoptions.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_dumpoptions.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_dumpoptions.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_load_dump.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_load_dump.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/easy_load_dump.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/easy_load_dump.cpp diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/hl_hdf5_inmemory_files.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/hl_hdf5_inmemory_files.cpp new file mode 100644 index 000000000..088fd71cc --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/hl_hdf5_inmemory_files.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c), 2022, Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include + +#include + +#include + +using namespace HighFive; + +class InMemoryFile: public HighFive::File { + public: + explicit InMemoryFile(std::vector buffer) + : _buffer(std::move(buffer)) { + _hid = H5LTopen_file_image(_buffer.data(), + sizeof(_buffer[0]) * _buffer.size(), + H5LT_FILE_IMAGE_DONT_RELEASE | H5LT_FILE_IMAGE_DONT_COPY); + } + + private: + std::vector _buffer; +}; + + +// Create a 2D dataset 10x3 of double with eigen matrix +// and write it to a file +int main(void) { + const std::string file_name("inmemory_file.h5"); + const std::string dataset_name("dset"); + + auto data = std::vector{1.0, 2.0, 3.0}; + + { + // We create an HDF5 file. + File file(file_name, File::Truncate); + file.createDataSet(dataset_name, data); + } + + // Simulate having an inmemory file by reading a file + // byte-by-byte into RAM. + auto buffer = std::vector(1ul << 20); + auto file = std::fopen(file_name.c_str(), "r"); + auto nread = std::fread(buffer.data(), sizeof(buffer[0]), buffer.size(), file); + std::cout << "Bytes read: " << nread << "\n"; + + // Create a file from a buffer. + auto h5 = InMemoryFile(std::move(buffer)); + + // Read a dataset as usual. + auto read_back = h5.getDataSet(dataset_name).read>(); + + // Check if the values match. + for (size_t i = 0; i < read_back.size(); ++i) { + if (read_back[i] != data[i]) { + throw std::runtime_error("Values don't match."); + } else { + std::cout << "read_back[" << i << "] = " << read_back[i] << "\n"; + } + } + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_collective_io.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_collective_io.cpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_collective_io.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_collective_io.cpp index 6eeecb0ce..7261b7cf1 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_collective_io.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_collective_io.cpp @@ -13,13 +13,10 @@ #include -#include -#include -#include -#include +#include -const std::string FILE_NAME("parallel_collective_example.h5"); -const std::string DATASET_NAME("dset"); +const std::string file_name("parallel_collective_example.h5"); +const std::string dataset_name("dset"); // Currently, HighFive doesn't wrap retrieving information from property lists. // Therefore, one needs to use HDF5 directly. For example, to see if collective @@ -55,6 +52,7 @@ int main(int argc, char** argv) { MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); using namespace HighFive; + try { // MPI-IO requires informing HDF5 that we want something other than // the default behaviour. This is done through property lists. We @@ -70,7 +68,7 @@ int main(int argc, char** argv) { fapl.add(MPIOCollectiveMetadata{}); // Now we can create the file as usual. - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate, fapl); + File file(file_name, File::Truncate, fapl); // We can create a group as usual, but all MPI ranks must participate. auto group = file.createGroup("grp"); @@ -81,7 +79,7 @@ int main(int argc, char** argv) { dims[1] = 2ul; // We follow the path for - DataSet dataset = group.createDataSet(DATASET_NAME, DataSpace(dims)); + DataSet dataset = group.createDataSet(dataset_name, DataSpace(dims)); // Each node want to write its own rank two time in // its associated row diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_independent_io.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_independent_io.cpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_independent_io.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_independent_io.cpp index 5c5537f3a..b43012890 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/parallel_hdf5_independent_io.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/parallel_hdf5_independent_io.cpp @@ -13,13 +13,9 @@ #include -#include -#include -#include -#include +#include -const std::string FILE_NAME("parallel_independent_example.h5"); -const std::string DATASET_NAME("dset"); +const std::string file_name("parallel_independent_example.h5"); // This is an example of how to let MPI ranks read independent parts of the // HDF5 file. @@ -41,7 +37,7 @@ int main(int argc, char** argv) { // ... // } if (mpi_rank == 0) { - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); + File file(file_name, File::ReadWrite | File::Create | File::Truncate); for (int i = 0; i < mpi_size; ++i) { std::stringstream group_name; @@ -74,7 +70,7 @@ int main(int argc, char** argv) { // fapl.add(MPIOCollectiveMetadataWrite{}); // Now we can create the file as usual. - File file(FILE_NAME, File::ReadOnly, fapl); + File file(file_name, File::ReadOnly, fapl); // Note that this operation isn't collective. Each MPI rank is requesting to // open a different group. diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_dataset_string.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_dataset_string.cpp new file mode 100644 index 000000000..2a4c3c491 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_dataset_string.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +using namespace HighFive; + +const std::string file_name("create_dataset_string_example.h5"); +const std::string dataset_name("story"); + +// create a dataset from a vector of string +// read it back and print it +int main(void) { + // Create a new file using the default property lists. + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + std::vector string_list; + string_list.push_back("Hello World !"); + string_list.push_back( + "This string list is mapped to a dataset of " + "variable length string"); + string_list.push_back("Encoding is done in UTF-8 - 你好 - Здравствуйте!"); + string_list.push_back("May the force be with you"); + string_list.push_back("Enjoy !"); + + // create a dataset ready to contains strings of the size of the vector + // string_list + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(string_list)); + + // let's write our vector of string + dataset.write(string_list); + + // now we read it back + std::vector result_string_list; + dataset.read(result_string_list); + + for (size_t i = 0; i < result_string_list.size(); ++i) { + std::cout << ":" << i << " " << result_string_list[i] << "\n"; + } + + return 0; // successfully terminated +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_fixedlen_string.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_fixedlen_string.cpp new file mode 100644 index 000000000..60589637e --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_fixedlen_string.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c), 2020, Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include + +#include + +using namespace HighFive; + +// This examples shows how compile time constant strings work. +// +// Note, that as of version 2.8.0., writing `std::string` as fixed-length +// strings there's a simpler API. +int main() { + // Create a new file using the default property lists. + File file("create_dataset_string_example.h5", File::Truncate); + const char strings_fixed[][16] = {"abcabcabcabcabc", "123123123123123"}; + + // create a dataset ready to contains strings of the size of the vector + file.createDataSet("ds1", DataSpace(2)).write(strings_fixed); + + // Without specific type info this will create an int8 dataset + file.createDataSet("ds2", strings_fixed); + + // Now test the new interface type + FixedLenStringArray<10> arr{"0000000", "1111111"}; + auto ds = file.createDataSet("ds3", arr); + + // Read back truncating to 4 chars + FixedLenStringArray<4> array_back; + ds.read(array_back); + std::cout << "First item is '" << array_back[0] << "'\n" + << "Second item is '" << array_back[1] << "'\n"; + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_raw_ptr.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_raw_ptr.cpp new file mode 100644 index 000000000..b6cd9eda5 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_raw_ptr.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * Copyright (c), 2022, Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +const std::string file_name("read_write_raw_ptr.h5"); +const std::string dataset_name("array"); + +// This create a "multi-dimensional" array. Meaning a pointer with +// dimensions. The `std::vector` is mearly a convenient way +// of allocating and releasing memory. +// +// Conceptionually this is only a raw pointer with dimensions. The +// data is store in row-major, aka C-style, without stride, offset +// or padding. +std::vector make_array(const std::vector& dims) { + auto n_elements = dims[0] * dims[1]; + std::vector nd_array(n_elements, 0.0); + + for (size_t i = 0; i < dims[0]; ++i) { + for (size_t j = 0; j < dims[1]; ++j) { + nd_array[j + i * dims[1]] = double(j) + 100.0 * double(i); + } + } + + return nd_array; +} + +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + // Let's write to file. + { + std::vector dims{3, 5}; + auto nd_array = make_array(dims); + + // First, create a dataset with the correct dimensions. + auto dataset = file.createDataSet(dataset_name, DataSpace(dims)); + + // Then write, using the raw pointer. + dataset.write_raw(nd_array.data()); + } + + // Let's read from file. + { + auto dataset = file.getDataSet(dataset_name); + + // First read the dimensions. + auto dims = dataset.getDimensions(); + + // Then allocate memory. + auto n_elements = dims[0] * dims[1]; + auto nd_array = std::vector(n_elements); + + // Finally, read into the memory by passing a raw pointer to the library. + dataset.read(nd_array.data()); + } + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_single_scalar.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_single_scalar.cpp new file mode 100644 index 000000000..4b4c6887c --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_single_scalar.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include + +const std::string file_name("read_write_scalar.h5"); +const std::string dataset_name("single_scalar"); + +// Create a dataset name "single_scalar" +// which contains only the perfect integer number "42" +// +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + int perfect_number = 42; + + // Create the dataset + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(perfect_number)); + + // write it + dataset.write(perfect_number); + + // flush everything + file.flush(); + + // let's read it back + int potentially_perfect_number; + + dataset.read(potentially_perfect_number); + + std::cout << "perfect number: " << potentially_perfect_number << std::endl; + + return 0; // successfully terminated +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_std_strings.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_std_strings.cpp new file mode 100644 index 000000000..7699e0c0c --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_std_strings.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (c), 2023, Blue Brain Project, EPFL + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include + +#include +#include +#include + +using namespace HighFive; + +// This example shows how to write (containers of) `std::string` +// to dataset either as fixed or variable length HDF5 strings. +// The feature is available from 2.8.0 onwards. +int main(void) { + auto file = File("read_write_std_string.h5", File::Truncate); + + // A string of length 3 in a buffer of size 4 bytes. We'll use "length" for + // the semantic length of the string, i.e. excluding the '\0' character and + // "size" to refer to the length of the buffer in which the string is stored. + // For null-terminated strings, the `size == length + 1`. + std::string ascii_string = "foo"; + auto scalar_dataspace = DataSpace(DataSpace::dataspace_scalar); + + // Just write the string: + file.createDataSet("single_automatic", ascii_string); + + // The above results in writing the string as an HDF5 variable length UTF8 + // string. In HDF5 a variable length string doesn't specify the length of + // the string. Variable length strings are always null-terminated. + auto variable_stringtype = VariableLengthStringType(); + file.createDataSet("single_variable", scalar_dataspace, variable_stringtype) + .write(ascii_string); + + // HDF5 also has the concept of fixed length string. In fixed length strings + // the size of the string, in bytes, is part of the datatype. The HDF5 API + // for fixed and variable length strings is distinct. Hence, when writing + // string that need to be read by other programs, it can matter if the string + // is stored as fixed or variable length. + // + // Important: The HDF5 string size is the size of the buffer required to + // store the string. + // + // We know that ascii_string requires 4 bytes to store, but want to store + // it in fixed length strings of length 8. Additionally, we promise that + // the strings are null-terminated. The character set defaults to ASCII. + auto fixed_stringtype = FixedLengthStringType(8, StringPadding::NullTerminated); + file.createDataSet("single_fixed_nullterm", scalar_dataspace, fixed_stringtype) + .write(ascii_string); + + // When reading into an `std::string` it doesn't matter if the HDF5 datatype + // is fixed or variable length. HighFive will internally read into a buffer + // and then write to the final destination. + auto from_variable = file.getDataSet("single_variable").read(); + auto from_fixed = file.getDataSet("single_fixed_nullterm").read(); + + // Note that because the fixed length string is null-terminated, + // `from_fixed.size() == ascii_string.size()` despite it being stored as a string of + // length 8. + std::cout << "from_variable = '" << from_variable << "' size = " << from_variable.size() + << "\n"; + std::cout << "from_fixed = '" << from_fixed << "' size = " << from_fixed.size() << "\n"; + + // Fixed-length string don't have to be null-terminated. Their length could + // be defined simply by the known size of the buffer required to store the + // string. To deal with the situation where the string is shorter than the + // buffer, one defines a padding character. This must be either the null or + // space character. We'll show null-padded, space-padded works the same way. + auto fixed_nullpad = FixedLengthStringType(8, StringPadding::NullPadded); + file.createDataSet("single_fixed_nullpad", scalar_dataspace, fixed_nullpad).write(ascii_string); + + // Note that because we only know that the string is padded with nulls, but we + // don't know if those nulls were part of the string to begin with. The full + // size of the buffer is read into the `std::string`. The length of the + // `std::string` is the size of the string type. + auto from_nullpad = file.getDataSet("single_fixed_nullpad").read(); + std::cout << "from_nullpad = '" << from_nullpad << "' size = " << from_nullpad.size() << "\n"; + + // Let's look at UTF8 strings. In HDF5 the size of a string is the size in + // bytes of the buffer required to store the string. A UTF8 symbol/character + // requires 1 to 4 bytes. + // + // The 'a' is 1 byte, the 'α' 2 bytes, therefore a total of 3 bytes (same + // as `utf8_string.size()`). Which including the null character fits into + // 8 bytes. However, 8 bytes would, in general not be enough to store 2 + // UTF8 characters and the null character. Which would require 9 bytes. + std::string utf8_string = "aα"; + auto fixed_utf8_type = + FixedLengthStringType(8, StringPadding::NullTerminated, CharacterSet::Utf8); + file.createDataSet("single_fixed_utf8", scalar_dataspace, fixed_utf8_type).write(utf8_string); + + auto from_utf8 = file.getDataSet("single_fixed_utf8").read(); + std::cout << "from_utf8 = '" << from_utf8 << "' size = " << from_utf8.size() << "\n"; + + // Finally, containers of `std::string`s work analogously: + auto ascii_strings = std::vector{"123", "456"}; + file.createDataSet("multi_fixed_nullterm", DataSpace::From(ascii_strings), fixed_stringtype) + .write(ascii_strings); + + auto ascii_strings_from_fixed = + file.getDataSet("multi_fixed_nullterm").read>(); + + // In order to see details of how each is stored in the HDF5 file use: + // h5dump read_write_std_string.h5 + + return 0; +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset.cpp similarity index 64% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset.cpp index 4ed57a9b3..9718c1c2b 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset.cpp @@ -10,20 +10,18 @@ #include #include -#include -#include -#include +#include using namespace HighFive; -const std::string FILE_NAME("dataset_integer.h5"); -const std::string DATASET_NAME("dset"); +const std::string file_name("dataset_integer.h5"); +const std::string dataset_name("dset"); const size_t size_dataset = 20; // create a dataset 1D from a vector of string void write_dataset() { // we create a new hdf5 file - File file(FILE_NAME, File::ReadWrite | File::Create | File::Truncate); + File file(file_name, File::ReadWrite | File::Create | File::Truncate); std::vector data(size_dataset); for (size_t i = 0; i < data.size(); ++i) { @@ -32,7 +30,7 @@ void write_dataset() { // let's create a dataset of native integer with the size of the vector // 'data' - DataSet dataset = file.createDataSet(DATASET_NAME, DataSpace::From(data)); + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(data)); // let's write our vector of int to the HDF5 dataset dataset.write(data); @@ -41,12 +39,12 @@ void write_dataset() { // read our data back void read_dataset() { // we open the existing hdf5 file we created before - File file(FILE_NAME, File::ReadOnly); + File file(file_name, File::ReadOnly); std::vector read_data; // we get the dataset - DataSet dataset = file.getDataSet(DATASET_NAME); + DataSet dataset = file.getDataSet(dataset_name); // we convert the hdf5 dataset to a single dimension vector dataset.read(read_data); @@ -58,14 +56,8 @@ void read_dataset() { } int main(void) { - try { - write_dataset(); - read_dataset(); + write_dataset(); + read_dataset(); - } catch (Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - - return 0; // successfully terminated + return 0; } diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset_references.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset_references.cpp similarity index 85% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset_references.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset_references.cpp index 8733dc275..ca0846768 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/read_write_vector_dataset_references.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/read_write_vector_dataset_references.cpp @@ -10,10 +10,7 @@ #include #include -#include -#include -#include -#include +#include // create a dataset 1D from a vector of int void write_dataset() { @@ -69,13 +66,8 @@ void read_dataset() { } int main() { - try { - write_dataset(); - read_dataset(); + write_dataset(); + read_dataset(); - } catch (const HighFive::Exception& err) { - // catch and print any HDF5 error - std::cerr << err.what() << std::endl; - } - return 0; // successfully terminated + return 0; } diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/readme_snippet.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/readme_snippet.cpp similarity index 70% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/readme_snippet.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/readme_snippet.cpp index 47187ee44..160dabce5 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/readme_snippet.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/readme_snippet.cpp @@ -1,4 +1,4 @@ -#include +#include using namespace HighFive; @@ -22,9 +22,10 @@ int main() { // Read back, with allocating: auto data = dataset.read>(); - // Because `data` has the correct size, this will - // not cause `data` to be reallocated: - dataset.read(data); + // Because `pre_allocated` has the correct size, this will + // not cause `pre_allocated` to be reallocated: + auto pre_allocated = std::vector(50); + dataset.read(pre_allocated); } return 0; diff --git a/modules/drivers/highfive/HighFive-2.7.1/src/examples/renaming_objects.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/renaming_objects.cpp similarity index 94% rename from modules/drivers/highfive/HighFive-2.7.1/src/examples/renaming_objects.cpp rename to modules/drivers/highfive/HighFive-2.8.0/src/examples/renaming_objects.cpp index 0f2a93ac7..f0759e52a 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/src/examples/renaming_objects.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/renaming_objects.cpp @@ -1,8 +1,4 @@ -#include -#include -#include -#include -#include +#include using namespace HighFive; diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_by_id_dataset_cpp11.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_by_id_dataset_cpp11.cpp new file mode 100644 index 000000000..973c57435 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_by_id_dataset_cpp11.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include +#include + +#include + +const std::string file_name("select_partial_string.h5"); +const std::string dataset_name("message"); + +// Create a dataset name "dset" of double 4x6 +// +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(file_name, File::Truncate); + + { + // We have a set of string + std::vector values = { + "Cat", + "Dog", + "Hello", + "Tree", + "World", + "Plane", + ", ", + "你好", + "Tea", + "Moon", + "صباح جميل", + "Spaceship", + }; + + // let's create a dataset + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); + + // and write them + dataset.write(values); + } + + { + DataSet dataset = file.getDataSet(dataset_name); + + // now let's read back by cherry pick our interesting string + std::vector result; + // we select only element N° 2 and 5 + dataset.select(ElementSet({2, 4, 6, 7, 6, 10})).read(result); + + // and display it + for (auto i: result) { + std::cout << i << " "; + } + std::cout << "\n"; + } + + return 0; // successfully terminated +} diff --git a/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_partial_dataset_cpp11.cpp b/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_partial_dataset_cpp11.cpp new file mode 100644 index 000000000..1e480c160 --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/src/examples/select_partial_dataset_cpp11.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c), 2017, Adrien Devresse + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#include +#include +#include +#include + +#include + +const std::string file_name("select_partial_example.h5"); +const std::string dataset_name("dset"); + +// Create a dataset name "dset" of double 4x6 +// +int main(void) { + using namespace HighFive; + + // Create a new file using the default property lists. + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + // we have some example values in a 2D vector 2x5 + std::vector> values = {{1.0, 2.0, 4.0, 8.0, 16.0}, + {32.0, 64.0, 128.0, 256.0, 512.0}}; + + // let's create a dataset of this size + DataSet dataset = file.createDataSet(dataset_name, DataSpace::From(values)); + // and write them + dataset.write(values); + + // now we read back 2x2 values after an offset of 0x2 + std::vector> result; + dataset.select({0, 2}, {2, 2}).read(result); + + // we print out 4 values + for (auto i: result) { + for (auto j: i) { + std::cout << " " << j; + } + std::cout << "\n"; + } + + return 0; // successfully terminated +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/CMakeLists.txt b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/CMakeLists.txt similarity index 97% rename from modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/CMakeLists.txt rename to modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/CMakeLists.txt index 1231a1419..570dba224 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/CMakeLists.txt +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/CMakeLists.txt @@ -15,7 +15,7 @@ option(USE_BUNDLED_HIGHFIVE "Use highfive from deps folder. Otherwise must be in if(USE_BUNDLED_HIGHFIVE) add_subdirectory("deps/HighFive" EXCLUDE_FROM_ALL) else() - find_package(HighFive REQUIRED) + find_package(HighFive REQUIRED QUIET) endif() add_library(simpleton SHARED "src/simpleton.cpp" "src/otherton.cpp") diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/deps/.gitignore b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/deps/.gitignore similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/deps/.gitignore rename to modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/deps/.gitignore diff --git a/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/include/simpleton.hpp b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/include/simpleton.hpp new file mode 100644 index 000000000..b98a09fda --- /dev/null +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/include/simpleton.hpp @@ -0,0 +1,14 @@ +#ifndef H5_TEST_SIMPLETON_HPP +#define H5_TEST_SIMPLETON_HPP + +// Include all headers here to catch any missing `inline` statements, since +// they will be included by two different compilation units. +#include + +// Boost should always be found in this setup +#include + +void function(const HighFive::Object& obj); +void other_function(const boost::numeric::ublas::matrix& m); + +#endif diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/src/otherton.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/src/otherton.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/src/otherton.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/src/otherton.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/src/simpleton.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/src/simpleton.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/tests/test_dependent_library/src/simpleton.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/test_dependent_library/src/simpleton.cpp diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/test_project_integration.sh b/modules/drivers/highfive/HighFive-2.8.0/tests/test_project_integration.sh similarity index 95% rename from modules/drivers/highfive/HighFive-2.7.1/tests/test_project_integration.sh rename to modules/drivers/highfive/HighFive-2.8.0/tests/test_project_integration.sh index 0d2b51af3..ae88695a0 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/test_project_integration.sh +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/test_project_integration.sh @@ -11,7 +11,7 @@ test_install() { local builddir="${BUILDDIR}/${project}/${2}" shift shift - ln -s ../../.. "${TESTDIR}/${project}/deps/HighFive" + ln -sf ../../.. "${TESTDIR}/${project}/deps/HighFive" rm -rf "${builddir}" mkdir -p "${builddir}" pushd "${builddir}" diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/CMakeLists.txt b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/CMakeLists.txt similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/CMakeLists.txt rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/CMakeLists.txt index 7f24abf97..3644d117c 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/CMakeLists.txt +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/CMakeLists.txt @@ -1,5 +1,6 @@ include(CTest) include(Catch) +include(HighFiveWarnings) if(MSVC) add_definitions(/bigobj) @@ -8,7 +9,7 @@ endif() ## Base tests foreach(test_name tests_high_five_base tests_high_five_multi_dims tests_high_five_easy test_all_types) add_executable(${test_name} "${test_name}.cpp") - target_link_libraries(${test_name} HighFive Catch2::Catch2WithMain) + target_link_libraries(${test_name} HighFive HighFiveWarnings Catch2::Catch2WithMain) catch_discover_tests(${test_name}) endforeach() @@ -18,7 +19,7 @@ if(HIGHFIVE_PARALLEL_HDF5) ## parallel MPI tests add_executable(tests_parallel_bin ${tests_parallel_src}) - target_link_libraries(tests_parallel_bin HighFive Catch2::Catch2) + target_link_libraries(tests_parallel_bin HighFive HighFiveWarnings Catch2::Catch2) # We need to patch in a call to `mpirun` or equivalent when using # parallel tests. Somehow, this is not foreseen in Catch2, modify the @@ -48,6 +49,6 @@ if(HIGHFIVE_TEST_SINGLE_INCLUDES) get_filename_component(CLASS_NAME ${PUBLIC_HEADER} NAME_WE) configure_file(tests_import_public_headers.cpp "tests_${CLASS_NAME}.cpp" @ONLY) add_executable("tests_include_${CLASS_NAME}" "${CMAKE_CURRENT_BINARY_DIR}/tests_${CLASS_NAME}.cpp") - target_link_libraries("tests_include_${CLASS_NAME}" HighFive) + target_link_libraries("tests_include_${CLASS_NAME}" HighFive HighFiveWarnings) endforeach() endif() diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/test_all_types.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/test_all_types.cpp similarity index 90% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/test_all_types.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/test_all_types.cpp index ed265e670..d74579af6 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/test_all_types.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/test_all_types.cpp @@ -8,21 +8,15 @@ */ #include -#include -#include -#include -#include -#include -#include - #include +#include #include "tests_high_five.hpp" using namespace HighFive; TEMPLATE_TEST_CASE("Scalar in DataSet", "[Types]", bool, std::string) { - const std::string FILE_NAME("Test_type.h5"); + const std::string FILE_NAME("rw_dataset_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); TestType t1{}; @@ -52,7 +46,7 @@ TEMPLATE_TEST_CASE("Scalar in DataSet", "[Types]", bool, std::string) { } TEMPLATE_PRODUCT_TEST_CASE("Scalar in std::vector", "[Types]", std::vector, (bool, std::string)) { - const std::string FILE_NAME("Test_vector.h5"); + const std::string FILE_NAME("rw_dataset_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); TestType t1(5); @@ -84,7 +78,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Scalar in std::vector", "[Types]", std::vector, (bool, std::string)) { - const std::string FILE_NAME("Test_vector_vector.h5"); + const std::string FILE_NAME("rw_dataset_vector_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); std::vector t1(5); for (auto&& e: t1) { @@ -118,7 +112,7 @@ TEMPLATE_PRODUCT_TEST_CASE("Scalar in std::vector", } TEMPLATE_TEST_CASE("Scalar in std::array", "[Types]", bool, std::string) { - const std::string FILE_NAME("Test_array.h5"); + const std::string FILE_NAME("rw_dataset_array_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); std::array t1{}; @@ -149,7 +143,7 @@ TEMPLATE_TEST_CASE("Scalar in std::array", "[Types]", bool, std::string) { } TEMPLATE_TEST_CASE("Scalar in std::vector", "[Types]", bool, std::string) { - const std::string FILE_NAME("Test_vector_array.h5"); + const std::string FILE_NAME("rw_dataset_vector_array_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); std::vector> t1(5); @@ -182,7 +176,7 @@ TEMPLATE_TEST_CASE("Scalar in std::vector", "[Types]", bool, std::st #if HIGHFIVE_CXX_STD >= 17 TEMPLATE_PRODUCT_TEST_CASE("Scalar in std::vector", "[Types]", std::vector, std::byte) { - const std::string FILE_NAME("Test_vector_byte.h5"); + const std::string FILE_NAME("rw_dataset_vector_" + typeNameHelper() + ".h5"); const std::string DATASET_NAME("dset"); TestType t1(5, std::byte(0xCD)); diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five.hpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five.hpp similarity index 95% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five.hpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five.hpp index 2d23c0879..0ebd58c44 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five.hpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five.hpp @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include // We don't need windows specific functionality. However, to better detect defects caused by macros, // we include this header. @@ -162,16 +165,22 @@ struct ContentGenerate { template inline std::string typeNameHelper() { std::string name = typeid(T).name(); -#if defined(WIN32) - // Replace illegal windows file path characters std::replace(std::begin(name), std::end(name), ' ', '_'); std::replace(std::begin(name), std::end(name), '<', '_'); std::replace(std::begin(name), std::end(name), '>', '_'); std::replace(std::begin(name), std::end(name), ':', '_'); -#endif - return name; + + if (name.size() > 64) { + std::stringstream hash; + hash << std::hex << std::hash{}(name); + + return hash.str(); + } else { + return name; + } } + template inline HighFive::DataSet readWriteDataset(const DataT& ndvec, DataT& result, @@ -193,4 +202,4 @@ inline HighFive::DataSet readWriteDataset(const DataT& ndvec, dataset.read(result); return dataset; -} \ No newline at end of file +} diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_base.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_base.cpp similarity index 82% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_base.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_base.cpp index 8c5706221..899170d93 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_base.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_base.cpp @@ -18,18 +18,11 @@ #include #include -#include -#include -#include -#include -#include -#include -#include - #include #include #include +#include #include "tests_high_five.hpp" using namespace HighFive; @@ -291,12 +284,12 @@ TEST_CASE("Test group properties") { File file(file_name, File::Truncate, fapl); GroupCreateProps props; - props.add(EstimatedLinkInfo(1000, 500)); + props.add(EstimatedLinkInfo(10, 60)); auto group = file.createGroup("g", props); auto sizes = group.getEstimatedLinkInfo(); - CHECK(sizes.first == 1000); - CHECK(sizes.second == 500); + CHECK(sizes.first == 10); + CHECK(sizes.second == 60); } TEST_CASE("Test allocation time") { @@ -317,13 +310,21 @@ TEST_CASE("Test allocation time") { CHECK(alloc_size == data.size() * sizeof(decltype(data)::value_type)); } +/* + * Test to ensure legacy support: DataSet used to have a default constructor. + * However, it is not useful to have a DataSet object that does not actually + * refer to a dataset in a file. Hence, the the default constructor was + * deprecated. + * This test is to ensure that the constructor is not accidentally removed and + * thereby break users' code. + */ TEST_CASE("Test default constructors") { - const std::string file_name("h5_group_test.h5"); + const std::string file_name("h5_default_ctors.h5"); const std::string dataset_name("dset"); File file(file_name, File::Truncate); auto ds = file.createDataSet(dataset_name, std::vector{1, 2, 3, 4, 5}); - DataSet d2; // deprecated as it constructs unsafe objects + DataSet d2; // expect deprecation warning, as it constructs unsafe object // d2.getFile(); // runtime error CHECK(!d2.isValid()); d2 = ds; // copy @@ -426,6 +427,67 @@ TEST_CASE("Test groups and datasets") { } } +TEST_CASE("FileSpace") { + const std::string filename = "filespace.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + File file(filename, File::Truncate); + file.createDataSet(ds_path, data); + + CHECK(file.getFileSize() > 0); +} + +TEST_CASE("FreeSpace (default)") { + const std::string filename = "freespace_default.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + { + File file(filename, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + } + + { + File file(filename, File::ReadWrite); + file.unlink(ds_path); + CHECK(file.getFreeSpace() > 0); + CHECK(file.getFreeSpace() < file.getFileSize()); + } +} + +#if H5_VERSION_GE(1, 10, 1) +TEST_CASE("FreeSpace (tracked)") { + const std::string filename = "freespace_tracked.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + { + FileCreateProps fcp; + fcp.add(FileSpaceStrategy(H5F_FSPACE_STRATEGY_FSM_AGGR, true, 0)); + File file(filename, File::Truncate, fcp); + auto dset = file.createDataSet(ds_path, data); + } + + { + File file(filename, File::ReadWrite); + file.unlink(ds_path); + +#if H5_VERSION_GE(1, 12, 0) + // This fails on 1.10.x but starts working in 1.12.0 + CHECK(file.getFreeSpace() > 0); +#endif + CHECK(file.getFreeSpace() < file.getFileSize()); + } + + { + File file(filename, File::ReadOnly); + CHECK(file.getFreeSpace() > 0); + CHECK(file.getFreeSpace() < file.getFileSize()); + } +} +#endif + TEST_CASE("Test extensible datasets") { const std::string file_name("create_extensible_dataset_example.h5"); const std::string dataset_name("dset"); @@ -633,6 +695,45 @@ TEST_CASE("Simple test for type equality") { CHECK(int_var != uint_var); } +TEST_CASE("StringType") { + SECTION("enshrine-defaults") { + auto fixed_length = FixedLengthStringType(32, StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + REQUIRE(fixed_length.getCharacterSet() == CharacterSet::Ascii); + REQUIRE(variable_length.getCharacterSet() == CharacterSet::Ascii); + } + + SECTION("fixed-length") { + auto fixed_length = + FixedLengthStringType(32, StringPadding::SpacePadded, CharacterSet::Utf8); + auto string_type = fixed_length.asStringType(); + + REQUIRE(string_type.getId() == fixed_length.getId()); + REQUIRE(string_type.getCharacterSet() == CharacterSet::Utf8); + REQUIRE(string_type.getPadding() == StringPadding::SpacePadded); + REQUIRE(string_type.getSize() == 32); + REQUIRE(!string_type.isVariableStr()); + REQUIRE(string_type.isFixedLenStr()); + } + + SECTION("variable-length") { + auto variable_length = VariableLengthStringType(CharacterSet::Utf8); + auto string_type = variable_length.asStringType(); + + REQUIRE(string_type.getId() == variable_length.getId()); + REQUIRE(string_type.getCharacterSet() == CharacterSet::Utf8); + REQUIRE(string_type.isVariableStr()); + REQUIRE(!string_type.isFixedLenStr()); + } + + SECTION("atomic") { + auto atomic = AtomicType(); + REQUIRE_THROWS(atomic.asStringType()); + } +} + + TEST_CASE("DataTypeEqualTakeBack") { const std::string file_name("h5tutr_dset.h5"); const std::string dataset_name("dset"); @@ -674,9 +775,11 @@ TEST_CASE("DataSpaceTest") { DataSpace space = dataset.getSpace(); DataSpace space2 = dataset.getSpace(); + auto space3 = space.clone(); // verify space id are different CHECK(space.getId() != space2.getId()); + CHECK(space.getId() != space3.getId()); // verify space id are consistent CHECK(space.getDimensions().size() == 2); @@ -684,6 +787,39 @@ TEST_CASE("DataSpaceTest") { CHECK(space.getDimensions()[1] == 1); } +TEST_CASE("DataSpace::getElementCount") { + SECTION("null") { + auto space = DataSpace(DataSpace::dataspace_null); + CHECK(space.getElementCount() == 0); + } + + SECTION("scalar") { + auto space = DataSpace(DataSpace::dataspace_scalar); + CHECK(space.getElementCount() == 1); + } + + SECTION("simple, empty (1D)") { + auto space = DataSpace(0); + CHECK(space.getElementCount() == 0); + } + + SECTION("simple, empty (2D)") { + auto space = DataSpace(0, 0); + CHECK(space.getElementCount() == 0); + } + + SECTION("simple, non-empty (2D)") { + auto space = DataSpace(2, 3); + CHECK(space.getElementCount() == 6); + } + + SECTION("FromCharArrayStrings") { + char string_array[2][10] = {"123456789", "abcdefghi"}; + auto space = DataSpace::FromCharArrayStrings(string_array); + CHECK(space.getElementCount() == 2); + } +} + TEST_CASE("DataSpaceVectorTest") { // Create 1D shortcut dataspace DataSpace space(7); @@ -934,6 +1070,34 @@ TEMPLATE_LIST_TEST_CASE("ReadWriteAttributeVector", "[template]", dataset_test_t readWriteAttributeVectorTest(); } +TEST_CASE("WriteLargeAttribute") { + std::vector large_attr(16000, 0.0); + + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); + HighFive::File file("create_large_attribute.h5", HighFive::File::Truncate, fapl); + auto gcpl = HighFive::GroupCreateProps::Default(); + gcpl.add(HighFive::AttributePhaseChange(0, 0)); + + auto group = file.createGroup("grp", gcpl); + CHECK_NOTHROW(group.createAttribute("attr", large_attr)); +} + +TEST_CASE("AttributePhaseChange") { + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); + HighFive::File file("attribute_phase_change.h5", HighFive::File::Truncate, fapl); + + auto gcpl = HighFive::GroupCreateProps::Default(); + gcpl.add(HighFive::AttributePhaseChange(42, 24)); + + auto group = file.createGroup("grp", gcpl); + + auto actual = AttributePhaseChange(group.getCreatePropertyList()); + CHECK(actual.min_dense() == 24); + CHECK(actual.max_compact() == 42); +} + TEST_CASE("datasetOffset") { std::string filename = "datasetOffset.h5"; std::string dsetname = "dset"; @@ -2211,8 +2375,72 @@ TEST_CASE("HighFiveSoftLinks") { } } +TEST_CASE("HighFiveHardLinks Dataset (create intermediate)") { + const std::string file_name("hardlinks_dataset_intermiate.h5"); + const std::string ds_path("/group/dataset"); + const std::string ds_link_path("/alternate/dataset"); + const std::vector data{12, 24, 36}; + + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + file.createHardLink(ds_link_path, dset); + file.unlink(ds_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(ds_link_path).read>(); + CHECK(data == data_out); + } +} + +TEST_CASE("HighFiveHardLinks Dataset (relative paths)") { + const std::string file_name("hardlinks_dataset_relative.h5"); + const std::string ds_path("/group/dataset"); + const std::string ds_link_path("/alternate/dataset"); + const std::vector data{12, 24, 36}; + + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + + auto alternate = file.createGroup("/alternate"); + alternate.createHardLink("dataset", dset); + file.unlink(ds_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(ds_link_path).read>(); + CHECK(data == data_out); + } +} + +TEST_CASE("HighFiveHardLinks Group") { + const std::string file_name("hardlinks_group.h5"); + const std::string group_path("/group"); + const std::string ds_name("dataset"); + const std::string group_link_path("/alternate"); + const std::vector data{12, 24, 36}; + + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(group_path + "/" + ds_name, data); + auto group = file.getGroup(group_path); + file.createHardLink(group_link_path, group); + file.unlink(group_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(group_link_path + "/" + ds_name).read>(); + CHECK(data == data_out); + } +} + TEST_CASE("HighFiveRename") { - File file("move.h5", File::ReadWrite | File::Create | File::Truncate); + File file("h5_rename.h5", File::ReadWrite | File::Create | File::Truncate); int number = 100; @@ -2237,7 +2465,7 @@ TEST_CASE("HighFiveRename") { } TEST_CASE("HighFiveRenameRelative") { - File file("move.h5", File::ReadWrite | File::Create | File::Truncate); + File file("h5_rename_relative.h5", File::ReadWrite | File::Create | File::Truncate); Group group = file.createGroup("group"); int number = 100; @@ -2424,6 +2652,10 @@ TEST_CASE("HighFiveCompounds") { CompoundType t2_from_hid(t2); CHECK(t2 == t2_from_hid); + + // Back from a DataType + CHECK_NOTHROW(CompoundType(DataType(t1_from_hid))); + CHECK_THROWS(CompoundType(AtomicType{})); } struct GrandChild { @@ -2676,6 +2908,250 @@ TEST_CASE("HighFiveEnum") { } } +TEST_CASE("HighFiveReadType") { + const std::string file_name("readtype_test.h5"); + const std::string datatype_name1("my_type"); + const std::string datatype_name2("position"); + + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + CompoundType t1 = create_compound_csl1(); + t1.commit(file, datatype_name1); + + CompoundType t2 = file.getDataType(datatype_name1); + + auto t3 = create_enum_position(); + t3.commit(file, datatype_name2); + + DataType t4 = file.getDataType(datatype_name2); + + CHECK(t2 == t1); + CHECK(t4 == t3); +} + +class ForwardToAttribute { + public: + ForwardToAttribute(const HighFive::File& file) + : _file(file) {} + + template + HighFive::Attribute create(const std::string& name, const T& value) { + return _file.createAttribute(name, value); + } + + HighFive::Attribute create(const std::string& name, + const HighFive::DataSpace filespace, + const HighFive::DataType& datatype) { + return _file.createAttribute(name, filespace, datatype); + } + + HighFive::Attribute get(const std::string& name) { + return _file.getAttribute(name); + } + + private: + HighFive::File _file; +}; + +class ForwardToDataSet { + public: + ForwardToDataSet(const HighFive::File& file) + : _file(file) {} + + template + HighFive::DataSet create(const std::string& name, const T& value) { + return _file.createDataSet(name, value); + } + + HighFive::DataSet create(const std::string& name, + const HighFive::DataSpace filespace, + const HighFive::DataType& datatype) { + return _file.createDataSet(name, filespace, datatype); + } + + HighFive::DataSet get(const std::string& name) { + return _file.getDataSet(name); + } + + private: + HighFive::File _file; +}; + +template +void check_single_string(Proxy proxy, size_t string_length) { + auto value = std::string(string_length, 'o'); + auto dataspace = DataSpace::From(value); + + auto n_chars = value.size() + 1; + auto n_chars_overlength = n_chars + 10; + auto fixed_length = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto overlength_nullterm = FixedLengthStringType(n_chars_overlength, + StringPadding::NullTerminated); + auto overlength_nullpad = FixedLengthStringType(n_chars_overlength, StringPadding::NullPadded); + auto overlength_spacepad = FixedLengthStringType(n_chars_overlength, + StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + SECTION("automatic") { + proxy.create("auto", value); + REQUIRE(proxy.get("auto").template read() == value); + } + + SECTION("fixed length") { + proxy.create("fixed", dataspace, fixed_length).write(value); + REQUIRE(proxy.get("fixed").template read() == value); + } + + SECTION("overlength null-terminated") { + proxy.create("overlength_nullterm", dataspace, overlength_nullterm).write(value); + REQUIRE(proxy.get("overlength_nullterm").template read() == value); + } + + SECTION("overlength null-padded") { + proxy.create("overlength_nullpad", dataspace, overlength_nullpad).write(value); + auto expected = std::string(n_chars_overlength, '\0'); + expected.replace(0, value.size(), value.data()); + REQUIRE(proxy.get("overlength_nullpad").template read() == expected); + } + + SECTION("overlength space-padded") { + proxy.create("overlength_spacepad", dataspace, overlength_spacepad).write(value); + auto expected = std::string(n_chars_overlength, ' '); + expected.replace(0, value.size(), value.data()); + REQUIRE(proxy.get("overlength_spacepad").template read() == expected); + } + + SECTION("variable length") { + proxy.create("variable", dataspace, variable_length).write(value); + REQUIRE(proxy.get("variable").template read() == value); + } +} + +template +void check_multiple_string(Proxy proxy, size_t string_length) { + using value_t = std::vector; + auto value = value_t{std::string(string_length, 'o'), std::string(string_length, 'x')}; + + auto dataspace = DataSpace::From(value); + + auto string_overlength = string_length + 10; + auto onpoint_nullpad = FixedLengthStringType(string_length, StringPadding::NullPadded); + auto onpoint_spacepad = FixedLengthStringType(string_length, StringPadding::SpacePadded); + + auto overlength_nullterm = FixedLengthStringType(string_overlength, + StringPadding::NullTerminated); + auto overlength_nullpad = FixedLengthStringType(string_overlength, StringPadding::NullPadded); + auto overlength_spacepad = FixedLengthStringType(string_overlength, StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + auto check = [](const value_t actual, const value_t& expected) { + REQUIRE(actual.size() == expected.size()); + for (size_t i = 0; i < actual.size(); ++i) { + REQUIRE(actual[i] == expected[i]); + } + }; + + SECTION("automatic") { + proxy.create("auto", value); + check(proxy.get("auto").template read(), value); + } + + SECTION("variable length") { + proxy.create("variable", dataspace, variable_length).write(value); + check(proxy.get("variable").template read(), value); + } + + auto make_padded_reference = [&](char pad, size_t n) { + auto expected = std::vector(value.size(), std::string(n, pad)); + for (size_t i = 0; i < value.size(); ++i) { + expected[i].replace(0, value[i].size(), value[i].data()); + } + + return expected; + }; + + auto check_fixed_length = [&](const std::string& label, size_t length) { + SECTION(label + " null-terminated") { + auto datatype = FixedLengthStringType(length + 1, StringPadding::NullTerminated); + proxy.create(label + "_nullterm", dataspace, datatype).write(value); + check(proxy.get(label + "_nullterm").template read(), value); + } + + SECTION(label + " null-padded") { + auto datatype = FixedLengthStringType(length, StringPadding::NullPadded); + proxy.create(label + "_nullpad", dataspace, datatype).write(value); + auto expected = make_padded_reference('\0', length); + check(proxy.get(label + "_nullpad").template read(), expected); + } + + SECTION(label + " space-padded") { + auto datatype = FixedLengthStringType(length, StringPadding::SpacePadded); + proxy.create(label + "_spacepad", dataspace, datatype).write(value); + auto expected = make_padded_reference(' ', length); + check(proxy.get(label + "_spacepad").template read(), expected); + } + }; + + check_fixed_length("onpoint", string_length); + check_fixed_length("overlength", string_length + 5); + + + SECTION("underlength null-terminated") { + auto datatype = FixedLengthStringType(string_length, StringPadding::NullTerminated); + REQUIRE_THROWS(proxy.create("underlength_nullterm", dataspace, datatype).write(value)); + } + + SECTION("underlength nullpad") { + auto datatype = FixedLengthStringType(string_length - 1, StringPadding::NullPadded); + REQUIRE_THROWS(proxy.create("underlength_nullpad", dataspace, datatype).write(value)); + } + + SECTION("underlength spacepad") { + auto datatype = FixedLengthStringType(string_length - 1, StringPadding::NullTerminated); + REQUIRE_THROWS(proxy.create("underlength_spacepad", dataspace, datatype).write(value)); + } +} + +TEST_CASE("HighFiveSTDString (dataset, single, short)") { + File file("std_string_dataset_single_short.h5", File::Truncate); + check_single_string(ForwardToDataSet(file), 3); +} + +TEST_CASE("HighFiveSTDString (attribute, single, short)") { + File file("std_string_attribute_single_short.h5", File::Truncate); + check_single_string(ForwardToAttribute(file), 3); +} + +TEST_CASE("HighFiveSTDString (dataset, single, long)") { + File file("std_string_dataset_single_long.h5", File::Truncate); + check_single_string(ForwardToDataSet(file), 256); +} + +TEST_CASE("HighFiveSTDString (attribute, single, long)") { + File file("std_string_attribute_single_long.h5", File::Truncate); + check_single_string(ForwardToAttribute(file), 256); +} + +TEST_CASE("HighFiveSTDString (dataset, multiple, short)") { + File file("std_string_dataset_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToDataSet(file), 3); +} + +TEST_CASE("HighFiveSTDString (attribute, multiple, short)") { + File file("std_string_attribute_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToAttribute(file), 3); +} + +TEST_CASE("HighFiveSTDString (dataset, multiple, long)") { + File file("std_string_dataset_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToDataSet(file), 256); +} + +TEST_CASE("HighFiveSTDString (attribute, multiple, long)") { + File file("std_string_attribute_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToAttribute(file), 256); +} + TEST_CASE("HighFiveFixedString") { const std::string file_name("array_atomic_types.h5"); const std::string group_1("group1"); @@ -2710,6 +3186,7 @@ TEST_CASE("HighFiveFixedString") { file.createDataSet("ds4", DataSpace(2)).write(strings_fixed); } + { // Cant convert flex-length to fixed-length const char* buffer[] = {"abcd", "1234"}; SilenceHDF5 silencer; @@ -2724,8 +3201,6 @@ TEST_CASE("HighFiveFixedString") { { // Dedicated FixedLenStringArray FixedLenStringArray<10> arr{"0000000", "1111111"}; - // For completeness, test also the other constructor - FixedLenStringArray<10> arrx(std::vector{"0000", "1111"}); // More API: test inserting something arr.push_back("2222"); @@ -2753,6 +3228,72 @@ TEST_CASE("HighFiveFixedString") { CHECK((*iter)[1] == 'y'); } } + + { + // Direct way of writing `std::string` as a fixed length + // HDF5 string. + + std::string value = "foo"; + auto n_chars = value.size() + 1; + + auto datatype = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto dataspace = DataSpace(1); + + auto ds = file.createDataSet("ds8", dataspace, datatype); + ds.write_raw(value.data(), datatype); + + { + // Due to missing non-const overload of `data()` until C++17 we'll + // read into something else instead (don't forget the '\0'). + auto expected = std::vector(n_chars, '!'); + ds.read(expected.data(), datatype); + + CHECK(expected.size() == value.size() + 1); + for (size_t i = 0; i < value.size(); ++i) { + REQUIRE(expected[i] == value[i]); + } + } + +#if HIGHFIVE_CXX_STD >= 17 + { + auto expected = std::string(value.size(), '-'); + ds.read(expected.data(), datatype); + + REQUIRE(expected == value); + } +#endif + } + + { + size_t n_chars = 4; + size_t n_strings = 2; + + std::vector value(n_chars * n_strings, '!'); + + auto datatype = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto dataspace = DataSpace(n_strings); + + auto ds = file.createDataSet("ds9", dataspace, datatype); + ds.write_raw(value.data(), datatype); + + auto expected = std::vector(value.size(), '-'); + ds.read(expected.data(), datatype); + + CHECK(expected.size() == value.size()); + for (size_t i = 0; i < value.size(); ++i) { + REQUIRE(expected[i] == value[i]); + } + } +} + +template +static void check_fixed_len_string_array_contents(const FixedLenStringArray& array, + const std::vector& expected) { + REQUIRE(array.size() == expected.size()); + + for (size_t i = 0; i < array.size(); ++i) { + CHECK(array[i] == expected[i]); + } } TEST_CASE("HighFiveFixedLenStringArrayStructure") { @@ -2769,16 +3310,52 @@ TEST_CASE("HighFiveFixedLenStringArrayStructure") { return output; }; + SECTION("create from std::vector (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>(expected); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from std::vector (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>(expected); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from pointers (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>(expected.data(), expected.data() + expected.size()); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from pointers (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>(expected.data(), expected.data() + expected.size()); + check_fixed_len_string_array_contents(actual, expected); + } + + + SECTION("create from std::initializer_list (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>{"000", "111"}; + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from std::initializer_list (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>{"000", "111"}; + check_fixed_len_string_array_contents(actual, expected); + } + // manipulate FixedLenStringArray with std::copy - { + SECTION("compatible with std::copy") { const fixed_array_t arr1{"0000000", "1111111"}; fixed_array_t arr2{"0000000", "1111111"}; std::copy(arr1.begin(), arr1.end(), std::back_inserter(arr2)); CHECK(arr2.size() == 4); } - // manipulate FixedLenStringArray with std::transform - { + SECTION("compatible with std::transform") { fixed_array_t arr; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2789,8 +3366,7 @@ TEST_CASE("HighFiveFixedLenStringArrayStructure") { CHECK(arr[1] == std::string("2222222")); } - // manipulate FixedLenStringArray with std::transform and reverse iterator - { + SECTION("compatible with std::transform (reverse iterator)") { fixed_array_t arr; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2801,8 +3377,7 @@ TEST_CASE("HighFiveFixedLenStringArrayStructure") { CHECK(arr[1] == std::string("0000000")); } - // manipulate FixedLenStringArray with std::remove_copy_if - { + SECTION("compatible with std::remove_copy_if") { fixed_array_t arr2; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2987,7 +3562,7 @@ TEST_CASE("HighFiveEigen") { vec_in << 1, 2, 3, 4, 5, 6, 7, 8, 9; Eigen::Matrix vec_out; - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } // Eigen MatrixXd @@ -2996,7 +3571,7 @@ TEST_CASE("HighFiveEigen") { Eigen::MatrixXd vec_in = 100. * Eigen::MatrixXd::Random(20, 5); Eigen::MatrixXd vec_out(20, 5); - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } // std::vector @@ -3010,7 +3585,7 @@ TEST_CASE("HighFiveEigen") { vec_in.push_back(m2); std::vector vec_out(2, Eigen::MatrixXd::Zero(20, 5)); - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } #ifdef H5_USE_BOOST @@ -3044,13 +3619,15 @@ TEST_CASE("HighFiveEigen") { } } boost::multi_array vec_out(boost::extents[3][2][2]); - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) { vec_out[i][j][k] = Eigen::MatrixXd::Zero(3, 3); } } - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + } + + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } #endif diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_easy.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_easy.cpp similarity index 78% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_easy.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_easy.cpp index 64a770674..e003c3234 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_easy.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_easy.cpp @@ -56,40 +56,66 @@ TEST_CASE("H5Easy_Compression") { } TEST_CASE("H5Easy_scalar") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_scalar.h5", H5Easy::File::Overwrite); double a = 1.2345; int b = 12345; std::string c = "12345"; + std::complex d = std::complex(1.2345, -5.4321); + std::complex e = std::complex(12345, -54321); H5Easy::dump(file, "/path/to/a", a); H5Easy::dump(file, "/path/to/b", b); H5Easy::dump(file, "/path/to/c", c); H5Easy::dump(file, "/path/to/c", c, H5Easy::DumpMode::Overwrite); + H5Easy::dump(file, "/path/to/d", d); + H5Easy::dump(file, "/path/to/e", e); double a_r = H5Easy::load(file, "/path/to/a"); int b_r = H5Easy::load(file, "/path/to/b"); std::string c_r = H5Easy::load(file, "/path/to/c"); + std::complex d_r = H5Easy::load>(file, "/path/to/d"); + std::complex e_r = H5Easy::load>(file, "/path/to/e"); CHECK(a == a_r); CHECK(b == b_r); CHECK(c == c_r); + CHECK(d == d_r); + CHECK(e == e_r); } TEST_CASE("H5Easy_vector1d") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_vector1d.h5", H5Easy::File::Overwrite); std::vector a = {1, 2, 3, 4, 5}; + std::vector> b = {std::complex(1, .1), + std::complex(2, -.4), + std::complex(3, .9), + std::complex(4, -.16), + std::complex(5, .25)}; + std::vector> c = {std::complex(1, -5), + std::complex(2, -4), + std::complex(3, -3), + std::complex(4, -2), + std::complex(5, -1)}; H5Easy::dump(file, "/path/to/a", a); + H5Easy::dump(file, "/path/to/b", b); + H5Easy::dump(file, "/path/to/c", c); std::vector a_r = H5Easy::load>(file, "/path/to/a"); + std::vector> b_r = + H5Easy::load>>(file, "/path/to/b"); + std::vector> c_r = + H5Easy::load>>(file, "/path/to/c"); CHECK(a == a_r); + CHECK(b == b_r); + CHECK(c == c_r); } TEST_CASE("H5Easy_vector2d") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_vector2d.h5", H5Easy::File::Overwrite); std::vector> a({{0, 1}, {2, 3}, {4, 5}}); @@ -101,7 +127,7 @@ TEST_CASE("H5Easy_vector2d") { } TEST_CASE("H5Easy_vector2d_compression") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_vector2d_compression.h5", H5Easy::File::Overwrite); std::vector> a({{0, 1}, {2, 3}, {4, 5}}); @@ -118,7 +144,7 @@ TEST_CASE("H5Easy_vector2d_compression") { } TEST_CASE("H5Easy_vector3d") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_vector3d.h5", H5Easy::File::Overwrite); using type = std::vector>>; @@ -132,7 +158,7 @@ TEST_CASE("H5Easy_vector3d") { } TEST_CASE("H5Easy_Attribute_scalar") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_attribute_scalar.h5", H5Easy::File::Overwrite); double a = 1.2345; int b = 12345; @@ -155,7 +181,7 @@ TEST_CASE("H5Easy_Attribute_scalar") { #ifdef H5_USE_XTENSOR TEST_CASE("H5Easy_extend1d") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_extend1d.h5", H5Easy::File::Overwrite); for (size_t i = 0; i < 10; ++i) { H5Easy::dump(file, "/path/to/A", i, {i}); @@ -172,7 +198,7 @@ TEST_CASE("H5Easy_extend1d") { } TEST_CASE("H5Easy_extend2d") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_extend2d.h5", H5Easy::File::Overwrite); for (size_t i = 0; i < 10; ++i) { for (size_t j = 0; j < 5; ++j) { @@ -193,7 +219,7 @@ TEST_CASE("H5Easy_extend2d") { } TEST_CASE("H5Easy_xtensor") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_xtensor.h5", H5Easy::File::Overwrite); xt::xtensor A = 100. * xt::random::randn({20, 5}); xt::xtensor B = A; @@ -209,7 +235,7 @@ TEST_CASE("H5Easy_xtensor") { } TEST_CASE("H5Easy_xarray") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_xarray.h5", H5Easy::File::Overwrite); xt::xarray A = 100. * xt::random::randn({20, 5}); xt::xarray B = A; @@ -225,7 +251,7 @@ TEST_CASE("H5Easy_xarray") { } TEST_CASE("H5Easy_view") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_view.h5", H5Easy::File::Overwrite); xt::xtensor A = 100. * xt::random::randn({20, 5}); auto a = xt::view(A, xt::range(0, 10), xt::range(0, 10)); @@ -238,7 +264,7 @@ TEST_CASE("H5Easy_view") { } TEST_CASE("H5Easy_xtensor_compress") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_xtensor_compress.h5", H5Easy::File::Overwrite); xt::xtensor A = 100. * xt::random::randn({20, 5}); xt::xtensor B = A; @@ -260,7 +286,7 @@ TEST_CASE("H5Easy_xtensor_compress") { } TEST_CASE("H5Easy_Attribute_xtensor") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_attribute_xtensor.h5", H5Easy::File::Overwrite); xt::xtensor A = 100. * xt::random::randn({20, 5}); xt::xtensor B = A; @@ -280,7 +306,7 @@ TEST_CASE("H5Easy_Attribute_xtensor") { #ifdef H5_USE_EIGEN TEST_CASE("H5Easy_Eigen_MatrixX") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_MatrixX.h5", H5Easy::File::Overwrite); Eigen::MatrixXd A = 100. * Eigen::MatrixXd::Random(20, 5); Eigen::MatrixXi B = A.cast(); @@ -296,7 +322,7 @@ TEST_CASE("H5Easy_Eigen_MatrixX") { } TEST_CASE("H5Easy_Eigen_ArrayXX") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_ArrayXX.h5", H5Easy::File::Overwrite); Eigen::ArrayXXf A = 100. * Eigen::ArrayXXf::Random(20, 5); Eigen::ArrayXXi B = A.cast(); @@ -312,7 +338,7 @@ TEST_CASE("H5Easy_Eigen_ArrayXX") { } TEST_CASE("H5Easy_Eigen_ArrayX") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_ArrayX.h5", H5Easy::File::Overwrite); Eigen::ArrayXf A = Eigen::ArrayXf::Random(50); Eigen::ArrayXi B = A.cast(); @@ -329,7 +355,7 @@ TEST_CASE("H5Easy_Eigen_ArrayX") { TEST_CASE("H5Easy_Eigen_VectorX") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_VectorX.h5", H5Easy::File::Overwrite); Eigen::VectorXd A = 100. * Eigen::VectorXd::Random(20); Eigen::VectorXi B = A.cast(); @@ -348,7 +374,7 @@ TEST_CASE("H5Easy_Eigen_MatrixXRowMajor") { typedef Eigen::Matrix MatrixXd; typedef Eigen::Matrix MatrixXi; - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("H5Easy_Eigen_MatrixXRowMajor.h5", H5Easy::File::Overwrite); MatrixXd A = 100. * MatrixXd::Random(20, 5); MatrixXi B = A.cast(); @@ -367,7 +393,7 @@ TEST_CASE("H5Easy_Eigen_VectorXRowMajor") { typedef Eigen::Matrix VectorXd; typedef Eigen::Matrix VectorXi; - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_VectorXRowMajor.h5", H5Easy::File::Overwrite); VectorXd A = 100. * VectorXd::Random(20); VectorXi B = A.cast(); @@ -383,7 +409,7 @@ TEST_CASE("H5Easy_Eigen_VectorXRowMajor") { } TEST_CASE("H5Easy_Eigen_Map") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_eigen_Map.h5", H5Easy::File::Overwrite); std::vector A = {1, 2, 3, 4, 5, 6, 7, 8, 9}; Eigen::Map mapped_vector(A.data(), static_cast(A.size())); @@ -396,7 +422,7 @@ TEST_CASE("H5Easy_Eigen_Map") { } TEST_CASE("H5Easy_Attribute_Eigen_MatrixX") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_attribute_eigen_MatrixX.h5", H5Easy::File::Overwrite); Eigen::MatrixXd A = 100. * Eigen::MatrixXd::Random(20, 5); Eigen::MatrixXi B = A.cast(); @@ -415,7 +441,7 @@ TEST_CASE("H5Easy_Attribute_Eigen_MatrixX") { #ifdef H5_USE_OPENCV TEST_CASE("H5Easy_OpenCV_Mat_") { - H5Easy::File file("test.h5", H5Easy::File::Overwrite); + H5Easy::File file("h5easy_opencv_Mat_.h5", H5Easy::File::Overwrite); using T = typename cv::Mat_; @@ -436,6 +462,7 @@ TEST_CASE("H5Easy_OpenCV_Mat_") { H5Easy::dump(file, "/path/to/A", A); H5Easy::dumpAttribute(file, "/path/to/A", "attr", A); + T A_r = H5Easy::load(file, "/path/to/A"); T B_r = H5Easy::loadAttribute(file, "/path/to/A", "attr"); diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_multi_dims.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_multi_dims.cpp similarity index 98% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_multi_dims.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_multi_dims.cpp index 4a4b8231c..442f1c9cc 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_multi_dims.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_multi_dims.cpp @@ -10,8 +10,7 @@ #include #include -#include -#include +#include #ifdef H5_USE_BOOST diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_parallel.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_parallel.cpp similarity index 97% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_parallel.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_parallel.cpp index b5518f48c..8b096205e 100644 --- a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_high_five_parallel.cpp +++ b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_high_five_parallel.cpp @@ -13,15 +13,11 @@ #include #include -#include -#include -#include -#include - #include #include #include +#include #include "tests_high_five.hpp" using namespace HighFive; diff --git a/modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_import_public_headers.cpp b/modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_import_public_headers.cpp similarity index 100% rename from modules/drivers/highfive/HighFive-2.7.1/tests/unit/tests_import_public_headers.cpp rename to modules/drivers/highfive/HighFive-2.8.0/tests/unit/tests_import_public_headers.cpp diff --git a/modules/drivers/highfive/include/highfive/H5Attribute.hpp b/modules/drivers/highfive/include/highfive/H5Attribute.hpp index c20b6c8f2..810d388ae 100644 --- a/modules/drivers/highfive/include/highfive/H5Attribute.hpp +++ b/modules/drivers/highfive/include/highfive/H5Attribute.hpp @@ -40,72 +40,204 @@ namespace detail { Attribute make_attribute(hid_t hid); } // namespace detail +/// \brief Class representing an Attribute of a DataSet or Group /// -/// \brief Class representing an attribute of a dataset or group -/// +/// \sa AnnotateTraits::createAttribute, AnnotateTraits::getAttribute, AnnotateTraits::listAttributeNames, AnnotateTraits::hasAttribute, AnnotateTraits::deleteAttribute for create, get, list, check or delete Attribute class Attribute: public Object, public PathTraits { public: const static ObjectType type = ObjectType::Attribute; - /// - /// \brief return the name of the current attribute - /// \return the name of the attribute + /// \brief Get the name of the current Attribute. + /// \code{.cpp} + /// auto attr = dset.createAttribute("my_attribute", DataSpace::From(string_list)); + /// std::cout << attr.getName() << std::endl; // Will print "my_attribute" + /// \endcode + /// \since 2.2.2 std::string getName() const; + /// \brief The number of bytes required to store the attribute in the HDF5 file. + /// \code{.cpp} + /// size_t size = dset.createAttribute("foo", DataSpace(1, 2)).getStorageSize(); + /// \endcode + /// \since 1.0 size_t getStorageSize() const; - /// - /// \brief getDataType - /// \return return the datatype associated with this dataset - /// + /// \brief Get the DataType of the Attribute. + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); + /// auto dtype = attr.getDataType(); // Will be an hdf5 type deduced from int + /// \endcode + /// \since 1.0 DataType getDataType() const; - /// - /// \brief getSpace - /// \return return the dataspace associated with this dataset - /// + /// \brief Get the DataSpace of the current Attribute. + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(1, 2)); + /// auto dspace = attr.getSpace(); // This will be a DataSpace of dimension 1 * 2 + /// \endcode + /// \since 1.0 DataSpace getSpace() const; - /// - /// \brief getMemSpace - /// \return same than getSpace for DataSet, compatibility with Selection - /// class - /// + /// \brief Get the DataSpace of the current Attribute. + /// \note This is an alias of getSpace(). + /// \since 1.0 DataSpace getMemSpace() const; - /// \brief Return the attribute + /// \brief Get the value of the Attribute. + /// \code{.cpp} + /// Attribute attr = dset.getAttribute("foo"); + /// // The value will contains what have been written in the attribute + /// std::vector value = attr.read>(); + /// \endcode + /// \since 2.5.0 template T read() const; + /// \brief Get the value of the Attribute in a buffer. + /// + /// Read the attribute into an existing object. Only available for + /// supported types `T`. If `array` has preallocated the correct amount of + /// memory, then this routine should not trigger reallocation. Otherwise, + /// if supported, the object will be resized. /// - /// Read the attribute into a buffer /// An exception is raised if the numbers of dimension of the buffer and of - /// the attribute are different + /// the attribute are different. /// - /// The array type can be a N-pointer or a N-vector ( e.g int** integer two - /// dimensional array ) + /// \code{.cpp} + /// // Will read into `value` avoiding memory allocation if the dimensions + /// // match, i.e. if the attribute `"foo"` has three element. + /// std::vector value(3); + /// file.getAttribute("foo").read(value); + /// \endcode + /// \since 1.0 template void read(T& array) const; - /// \brief Read the attribute into a buffer + /// \brief Read the attribute into a pre-allocated buffer. + /// \param array A pointer to the first byte of sufficient pre-allocated memory. + /// \param mem_datatype The DataType of the array. + /// + /// \note This is the shallowest wrapper around `H5Aread`. If possible + /// prefer either Attribute::read() const or Attribute::read(T&) const. + /// + /// \code{.cpp} + /// auto attr = file.getAttribute("foo"); + /// + /// // Simulate custom allocation by the application. + /// size_t n_elements = attr.getSpace().getElementCount(); + /// int * ptr = (int*) malloc(n_elements*sizeof(int)); + /// + /// // Read into the pre-allocated memory. + /// attr.read(ptr, mem_datatype); + /// \endcode + /// \since 2.2.2 template - void read(T* array, const DataType& dtype = {}) const; + void read(T* array, const DataType& mem_datatype) const; + /// \brief Read the attribute into a buffer. + /// Behaves like Attribute::read(T*, const DataType&) const but + /// additionally this overload deduces the memory datatype from `T`. /// - /// Write the integrality N-dimension buffer to this attribute - /// An exception is raised if the numbers of dimension of the buffer and of - /// the attribute are different + /// \param array Pointer to the first byte of pre-allocated memory. + /// + /// \note If possible prefer either Attribute::read() const or Attribute::read(T&) const. + /// + /// \code{.cpp} + /// auto attr = file.getAttribute("foo"); + /// + /// // Simulate custom allocation by the application. + /// size_t n_elements = attr.getSpace().getElementCount(); + /// int * ptr = (int*) malloc(n_elements*sizeof(int)); + /// + /// // Read into the pre-allocated memory. + /// attr.read(ptr); + /// \endcode + /// \since 2.2.2 + template + void read(T* array) const; + + /// \brief Write the value into the Attribute. + /// + /// Write the value to the attribute. For supported types `T`, this overload + /// will write the value to the attribute. The datatype and dataspace are + /// deduced automatically. However, since the attribute has already been + /// created, the dimensions of `value` must match those of the attribute. + /// + /// \code{.cpp} + /// // Prefer the fused version if creating and writing the attribute + /// // at the same time. + /// dset.createAttribute("foo", std::vector{1, 2, 3}); /// - /// The array type can be a N-pointer or a N-vector ( e.g int** integer two - /// dimensional array ) + /// // To overwrite the value: + /// std::vector value{4, 5, 6}; + /// dset.getAttribute("foo").write(value); + /// \endcode + /// \since 1.0 template - void write(const T& buffer); + void write(const T& value); - /// \brief Write a buffer to this attribute + /// \brief Write from a raw pointer. + /// + /// Values that have been correctly arranged memory, can be written directly + /// by passing a raw pointer. + /// + /// \param buffer Pointer to the first byte of the value. + /// \param mem_datatype The DataType of the buffer. + /// + /// \note This is the shallowest wrapper around `H5Awrite`. It's useful + /// if you need full control. If possible prefer Attribute::write. + /// + /// \code{.cpp} + /// Attribute attr = dset.createAttribute("foo", DataSpace(2, 3)); + /// + /// // Simulate the application creating `value` and only exposing access + /// // to the raw pointer `ptr`. + /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; + /// int * ptr = (int*) value.data(); + /// + /// // Simply write the bytes to disk. + /// attr.write(ptr, AtomicType()); + /// \endcode + /// \since 2.2.2 template - void write_raw(const T* buffer, const DataType& dtype = {}); + void write_raw(const T* buffer, const DataType& mem_datatype); - /// \brief Get the list of properties for creation of this attribute + /// \brief Write from a raw pointer. + /// + /// Much like Attribute::write_raw(const T*, const DataType&). + /// Additionally, this overload attempts to automatically deduce the + /// datatype of the buffer. Note, that the file datatype is already set. + /// + /// \param buffer Pointer to the first byte. + /// + /// \note If possible prefer Attribute::write. + /// + /// \code{.cpp} + /// // Simulate the application creating `value` and only exposing access + /// // to the raw pointer `ptr`. + /// std::vector> value{{1, 2, 3}, {4, 5, 6}}; + /// int * ptr = (int*) value.data(); + /// + /// // Simply write the bytes to disk. + /// attr.write(ptr); + /// \endcode + /// \since 2.2.2 + template + void write_raw(const T* buffer); + + /// \brief The create property list used for this attribute. + /// + /// Some of HDF5 properties/setting of an attribute are defined by a + /// create property list. This method returns a copy of the create + /// property list used during creation of the attribute. + /// + /// \code{.cpp} + /// auto acpl = attr.getCreatePropertyList(); + /// + /// // For example to create another attribute with the same properties. + /// file.createAttribute("foo", 42, acpl); + /// \endcode + /// \since 2.5.0 AttributeCreateProps getCreatePropertyList() const { return details::get_plist(*this, H5Aget_create_plist); } diff --git a/modules/drivers/highfive/include/highfive/H5DataSpace.hpp b/modules/drivers/highfive/include/highfive/H5DataSpace.hpp index 9c1647205..95d04dbbb 100644 --- a/modules/drivers/highfive/include/highfive/H5DataSpace.hpp +++ b/modules/drivers/highfive/include/highfive/H5DataSpace.hpp @@ -19,90 +19,215 @@ namespace HighFive { +/// \brief Class representing the space (dimensions) of a DataSet /// -/// \brief Class representing the space (dimensions) of a dataset -/// +/// \code{.cpp} +/// // Create a DataSpace of dimension 1 x 2 x 3 +/// DataSpace dspace(1, 2, 3); +/// std::cout << dspace.getElementCount() << std::endl; // Print 1 * 2 * 3 = 6 +/// std::cout << dspace.getNumberDimensions() << std::endl; // Print 3 +/// std::vector dims = dspace.getDimensions(); // dims is {1, 2, 3} +/// \endcode class DataSpace: public Object { public: const static ObjectType type = ObjectType::DataSpace; + /// \brief Magic value to specify that a DataSpace can grow without limit. + /// + /// This value should be used with DataSpace::DataSpace(const std::vector& dims, const + /// std::vector& maxdims); + /// + /// \since 2.0 static const size_t UNLIMITED = SIZE_MAX; - /// dataspace type + /// \brief An enum to create scalar and null DataSpace with DataSpace::DataSpace(DataspaceType dtype). + /// + /// This enum is needed otherwise we will not be able to distringuish between both with normal + /// constructors. Both have a dimension of 0. + /// \since 1.3 enum DataspaceType { - dataspace_scalar, - dataspace_null + dataspace_scalar, ///< Value to create scalar DataSpace + dataspace_null, ///< Value to create null DataSpace // simple dataspace are handle directly from their dimensions }; - /// create a dataspace of N-dimensions - /// Each dimension is configured this way - /// size(dim1) = vec[0] - /// size(dim2) = vec[1] - /// etc... + /// \brief Create a DataSpace of N-dimensions from a std::vector. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(std::vector{1, 3}); + /// \endcode + /// \since 1.0 explicit DataSpace(const std::vector& dims); - // create a dataspace of N-dimensions + /// \brief Create a DataSpace of N-dimensions from a std::array. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(std::array{1, 3}); + /// \endcode + /// \since 2.3 template explicit DataSpace(const std::array& dims); - /// Make sure that DataSpace({1,2,3}) works on GCC. This is - /// the shortcut form of the vector initializer, but one some compilers (gcc) - /// this does not resolve correctly without this constructor. - DataSpace(const std::initializer_list& items); - - /// Allow directly listing 1 or more dimensions to initialize, - /// that is, DataSpace(1,2) means DataSpace(std::vector{1,2}). + /// \brief Create a DataSpace of N-dimensions from an initializer list. + /// \param dims Dimensions of the new DataSpace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace{1, 3}; + /// \endcode + /// \since 2.1 + DataSpace(const std::initializer_list& dims); + + /// \brief Create a DataSpace of N-dimensions from direct values. + /// \param dim1 The first dimension + /// \param dims The following dimensions + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// DataSpace(1, 3); + /// \endcode + /// \since 2.1 template explicit DataSpace(size_t dim1, Args... dims); - /// Create a dataspace from an iterator pair + /// \brief Create a DataSpace from a pair of iterators. + /// \param begin The beginning of the container + /// \param end The end of the container + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3 + /// std::vector v{1, 3}; + /// DataSpace(v.begin(), v.end()); + /// \endcode /// - /// Explicitly disable DataSpace(int_like, int_like) from trying to use this constructor + /// \since 2.0 + // Attention: Explicitly disable DataSpace(int_like, int_like) from trying + // to use this constructor template ::value, IT>::type> DataSpace(const IT begin, const IT end); - /// \brief Create a resizable N-dimensional dataspace + /// \brief Create a resizable N-dimensional DataSpace. /// \param dims Initial size of dataspace /// \param maxdims Maximum size of the dataspace + /// + /// \code{.cpp} + /// // Create a DataSpace with 2 dimensions: 1 and 3. + /// // It can later be resized up to a maximum of 10 x 10 + /// DataSpace(std::vector{1, 3}, std::vector{10, 10}); + /// \endcode + /// + /// \see UNLIMITED for a DataSpace that can be resized without limit. + /// \since 2.0 explicit DataSpace(const std::vector& dims, const std::vector& maxdims); + /// \brief Create a scalar or a null DataSpace. /// - /// \brief DataSpace create a scalar dataspace or a null dataset + /// This overload enables creating scalar or null data spaces, both have + /// dimension 0. /// - explicit DataSpace(DataspaceType dtype); - - /// Create a new DataSpace - /// with a different id available for modifications - DataSpace clone() const; + /// \param space_type The value from the enum + /// + /// \code{.cpp} + /// DataSpace(DataspaceType::dataspace_scalar); + /// \endcode + /// + /// \attention Avoid braced intialization in these cases, i.e. + /// \code{.cpp} + /// // This is not a scalar dataset: + /// DataSpace{DataspaceType::dataspace_scalar}; + /// \endcode + /// + /// \since 1.3 + explicit DataSpace(DataspaceType space_type); + /// \brief Create a copy of the DataSpace which will have different id. /// - /// \brief getNumberDimensions - /// \return the number of dimensions in the current dataspace + /// \code{.cpp} + /// DataSpace dspace1(1, 3); + /// auto dspace2 = dspace.clone(); + /// \endcode /// + /// \since 1.0 + DataSpace clone() const; + + /// \brief Returns the number of dimensions of a DataSpace. + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// size_t number_of_dim = dspace.getNumberDimensions(); // returns 2 + /// \endcode + /// \since 1.0 size_t getNumberDimensions() const; - /// \brief getDimensions - /// \return return a vector of N-element, each element is the size of the - /// associated dataset dimension + /// \brief Returns the size of the dataset in each dimension. + /// + /// For zero-dimensional datasets (e.g. scalar or null datasets) an empty + /// vector is returned. + /// + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// auto dims = dspace.getDimensions(); // returns {1, 3} + /// \endcode + /// + /// \sa DataSpace::getMaxDimensions + /// + /// \since 1.0 std::vector getDimensions() const; - /// \brief getElementCount - /// \return the total number of elements in the dataspace + /// \brief Return the number of elements in this DataSpace. + /// + /// \code{.cpp} + /// DataSpace dspace(1, 3); + /// size_t elementcount = dspace.getElementCount(); // return 1 x 3 = 3 + /// \endcode + /// \since 2.1 size_t getElementCount() const; - /// \brief getMaxDimensions - /// \return return a vector of N-element, each element is the size of the - /// associated dataset maximum dimension + /// \brief Returns the maximum size of the dataset in each dimension. + /// + /// This is the maximum size a dataset can be extended to, which may be + /// different from the current size of the dataset. + /// + /// \code{.cpp} + /// DataSpace dspace(std::vector{1, 3}, std::vector{UNLIMITED, 10}); + /// dspace.getMaxDimensions(); // Return {UNLIMITED, 10} + /// \endcode + /// + /// \sa DataSpace::getDimensions + /// \since 2.0 std::vector getMaxDimensions() const; - /// Create a dataspace matching a type accepted by details::inspector + /// \brief Automatically deduce the DataSpace from a container/value. + /// + /// Certain containers and scalar values are fully supported by HighFive. + /// For these containers, HighFive can deduce the dimensions from `value`. + /// + /// \code{.cpp} + /// double d = 42.0; + /// std::vector> v = {{4, 5, 6}, {7, 8, 9}}; + /// DataSpace::From(v); // A DataSpace of dimensions 2, 3. + /// DataSpace::From(d); // A scalar dataspace. + /// \endcode + /// + /// \since 1.0 template static DataSpace From(const T& value); + /// \brief Create a DataSpace from a value of type string array. + /// \param string_array An C-array of C-string (null-terminated). + /// + /// \code{.cpp} + /// char string_array[2][10] = {"123456789", "abcdefghi"}; + /// auto dspace = DataSpace::FromCharArrayStrings(string_array); // dspace is a DataSpace of + /// dimensions 2 + /// \endcode + /// \since 2.2 template - static DataSpace FromCharArrayStrings(const char (&)[N][Width]); + static DataSpace FromCharArrayStrings(const char (&string_array)[N][Width]); protected: DataSpace() = default; diff --git a/modules/drivers/highfive/include/highfive/H5DataType.hpp b/modules/drivers/highfive/include/highfive/H5DataType.hpp index 43f758e45..886107961 100644 --- a/modules/drivers/highfive/include/highfive/H5DataType.hpp +++ b/modules/drivers/highfive/include/highfive/H5DataType.hpp @@ -11,9 +11,12 @@ #include #include +#include + #include "H5Object.hpp" #include "bits/H5Utils.hpp" +#include "bits/string_padding.hpp" #include "H5PropertyList.hpp" namespace HighFive { @@ -47,6 +50,7 @@ inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) { return static_cast(static_cast(lhs) & static_cast(rhs)); } +class StringType; /// /// \brief HDF5 Data Type @@ -85,6 +89,11 @@ class DataType: public Object { /// bool isFixedLenStr() const; + /// + /// \brief Returns this datatype as a `StringType`. + /// + StringType asStringType() const; + /// /// \brief Check the DataType was default constructed. /// Such value might represent auto-detection of the datatype from a buffer @@ -106,8 +115,67 @@ class DataType: public Object { friend class File; friend class DataSet; friend class CompoundType; + template + friend class NodeTraits; +}; + + +enum class CharacterSet : std::underlying_type::type { + Ascii = H5T_CSET_ASCII, + Utf8 = H5T_CSET_UTF8, +}; + +class StringType: public DataType { + public: + /// + /// \brief For stings return the character set. + /// + CharacterSet getCharacterSet() const; + + /// + /// \brief For fixed length stings return the padding. + /// + StringPadding getPadding() const; + + protected: + using DataType::DataType; + friend class DataType; +}; + +class FixedLengthStringType: public StringType { + public: + /// + /// \brief Create a fixed length string datatype. + /// + /// The string will be `size` bytes long, regardless whether it's ASCII or + /// UTF8. In particular, a string with `n` UFT8 characters in general + /// requires `4*n` bytes. + /// + /// The string padding is subtle, essentially it's just a hint. A + /// nullterminated string is guaranteed to have one `'\0'` which marks the + /// semantic end of the string. The length of the buffer must be at least + /// `size` bytes regardless. HDF5 will read or write `size` bytes, + /// irrespective of the when the `\0` occurs. + /// + /// Note that when writing passing `StringPadding::NullTerminated` is a + /// guarantee to the reader that it contains a `\0`. Therefore, make sure + /// that the string really is nullterminated. Otherwise prefer a + /// null-padded string which only means states that the buffer is filled up + /// with 0 or more `\0`. + FixedLengthStringType(size_t size, + StringPadding padding, + CharacterSet character_set = CharacterSet::Ascii); }; +class VariableLengthStringType: public StringType { + public: + /// + /// \brief Create a variable length string HDF5 datatype. + /// + VariableLengthStringType(CharacterSet character_set = CharacterSet::Ascii); +}; + + /// /// \brief create an HDF5 DataType from a C++ type /// @@ -175,11 +243,14 @@ class CompoundType: public DataType { size_t n_members = static_cast(result); members.reserve(n_members); for (unsigned i = 0; i < n_members; i++) { - const char* name = H5Tget_member_name(_hid, i); + char* name = H5Tget_member_name(_hid, i); size_t offset = H5Tget_member_offset(_hid, i); hid_t member_hid = H5Tget_member_type(_hid, i); DataType member_type{member_hid}; - members.emplace_back(name, member_type, offset); + members.emplace_back(std::string(name), member_type, offset); + if (H5free_memory(name) < 0) { + throw DataTypeException("Could not free names from the compound datatype"); + } } } @@ -250,7 +321,7 @@ class EnumType: public DataType { } EnumType(std::initializer_list t_members) - : EnumType(std::vector({t_members})) {} + : EnumType(std::vector(t_members)) {} /// \brief Commit datatype into the given Object /// \param object Location to commit object into @@ -280,15 +351,20 @@ DataType create_and_check_datatype(); /// Although fixed-len arrays can be created 'raw' without the need for /// this structure, to retrieve results efficiently it must be used. /// +/// \tparam N Size of the string in bytes, including the null character. Note, +/// that all string must be null-terminated. +/// template class FixedLenStringArray { public: FixedLenStringArray() = default; /// - /// \brief Create a FixedStringArray from a raw contiguous buffer + /// \brief Create a FixedStringArray from a raw contiguous buffer. + /// + /// The argument `n_strings` specifies the number of strings. /// - FixedLenStringArray(const char array[][N], std::size_t length); + FixedLenStringArray(const char array[][N], std::size_t n_strings); /// /// \brief Create a FixedStringArray from a sequence of strings. diff --git a/modules/drivers/highfive/include/highfive/H5File.hpp b/modules/drivers/highfive/include/highfive/H5File.hpp index d8dac1696..9b393e5a3 100644 --- a/modules/drivers/highfive/include/highfive/H5File.hpp +++ b/modules/drivers/highfive/include/highfive/H5File.hpp @@ -110,6 +110,17 @@ class File: public Object, public NodeTraits, public AnnotateTraits return details::get_plist(*this, H5Fget_access_plist); } + /// \brief Get the size of this file in bytes + size_t getFileSize() const; + + /// \brief Get the amount of tracked, unused space in bytes. + /// + /// Note, this is a wrapper for `H5Fget_freespace` and returns the number + /// bytes in the free space manager. This might be different from the total + /// amount of unused space in the HDF5 file, since the free space manager + /// might not track everything or not track across open-close cycles. + size_t getFreeSpace() const; + protected: File() = default; using Object::Object; diff --git a/modules/drivers/highfive/include/highfive/H5PropertyList.hpp b/modules/drivers/highfive/include/highfive/H5PropertyList.hpp index 6122820e5..53b3c4a13 100644 --- a/modules/drivers/highfive/include/highfive/H5PropertyList.hpp +++ b/modules/drivers/highfive/include/highfive/H5PropertyList.hpp @@ -22,6 +22,67 @@ namespace HighFive { +/// \defgroup PropertyLists Property Lists +/// HDF5 is configured through what they call property lists. In HDF5 the +/// process has four steps: +/// +/// 1. Create a property list. As users we now have an `hid_t` identifying the +/// property list. +/// 2. Set properties as desired. +/// 3. Pass the HID to the HDF5 function to be configured. +/// 4. Free the property list. +/// +/// Note that the mental picture is that one creates a settings object, and +/// then passes those settings to a function such as `H5Dwrite`. In and of +/// themselves the settings don't change the behaviour of HDF5. Rather they +/// need to be used to take affect. +/// +/// The second aspect is that property lists represent any number of related +/// settings, e.g. there's property lists anything related to creating files +/// and another for accessing files, same for creating and accessing datasets, +/// etc. Settings that affect creating files, must be passed a file creation +/// property list, while settings that affect file access require a file access +/// property list. +/// +/// In HighFive the `PropertyList` works similar in that it's a object +/// representing the settings, i.e. internally it's just the property lists +/// HID. Just like in HDF5 one adds the settings to the settings object; and +/// then passes the settings object to the respective method. Example: +/// +/// +/// // Create an object which contains the setting to +/// // open files with MPI-IO. +/// auto fapl = FileAccessProps(); +/// fapl.add(MPIOFileAccess(MPI_COMM_WORLD, MPI_INFO_NULL); +/// +/// // To open a specific file with MPI-IO, we do: +/// auto file = File("foo.h5", File::ReadOnly, fapl); +/// +/// Note that the `MPIOFileAccess` object by itself doesn't affect the +/// `FileAccessProps`. Rather it needs to be explicitly added to the `fapl` +/// (the group of file access related settings), and then the `fapl` needs to +/// be passed to the constructor of `File` for the settings to take affect. +/// +/// This is important to understand when reading properties. Example: +/// +/// // Obtain the file access property list: +/// auto fapl = file.getAccessPropertyList() +/// +/// // Extracts a copy of the collective MPI-IO metadata settings from +/// // the group of file access related setting, i.e. the `fapl`: +/// auto mpio_metadata = MPIOCollectiveMetadata(fapl); +/// +/// if(mpio_metadata.isCollectiveRead()) { +/// // something specific if meta data is read collectively. +/// } +/// +/// // Careful, this only affects the `mpio_metadata` object, but not the +/// // `fapl`, and also not whether `file` uses collective MPI-IO for +/// // metadata. +/// mpio_metadata = MPIOCollectiveMetadata(false, false); +/// +/// @{ + /// /// \brief Types of property lists /// @@ -72,6 +133,26 @@ class PropertyListBase: public Object { friend T details::get_plist(const U&, hid_t (*f)(hid_t)); }; +/// \interface PropertyInterface +/// \brief HDF5 file property object +/// +/// A property is an object which is expected to have a method with the +/// following signature `void apply(hid_t hid) const` +/// +/// \sa Instructions to document C++20 concepts with Doxygen: https://github.com/doxygen/doxygen/issues/2732#issuecomment-509629967 +/// +/// \cond +#if HIGHFIVE_HAS_CONCEPTS && __cplusplus >= 202002L +template +concept PropertyInterface = requires(P p, const hid_t hid) { + {p.apply(hid)}; +}; + +#else +#define PropertyInterface typename +#endif +/// \endcond + /// /// \brief HDF5 property Lists /// @@ -88,8 +169,8 @@ class PropertyList: public PropertyListBase { /// Add a property to this property list. /// A property is an object which is expected to have a method with the /// following signature void apply(hid_t hid) const - /// - template + /// \tparam PropertyInterface + template void add(const P& property); /// @@ -377,6 +458,7 @@ class PageBufferSize { #endif /// \brief Set hints as to how many links to expect and their average length +/// \implements PropertyInterface /// class EstimatedLinkInfo { public: @@ -402,6 +484,7 @@ class EstimatedLinkInfo { }; +/// \implements PropertyInterface class Chunking { public: explicit Chunking(const std::vector& dims); @@ -420,6 +503,7 @@ class Chunking { std::vector _dims; }; +/// \implements PropertyInterface class Deflate { public: explicit Deflate(unsigned level); @@ -431,6 +515,7 @@ class Deflate { const unsigned _level; }; +/// \implements PropertyInterface class Szip { public: explicit Szip(unsigned options_mask = H5_SZIP_EC_OPTION_MASK, @@ -446,6 +531,7 @@ class Szip { const unsigned _pixels_per_block; }; +/// \implements PropertyInterface class Shuffle { public: Shuffle() = default; @@ -460,6 +546,7 @@ class Shuffle { /// The precise time of when HDF5 requests space to store the dataset /// can be configured. Please, consider the upstream documentation for /// `H5Pset_alloc_time`. +/// \implements PropertyInterface class AllocationTime { public: explicit AllocationTime(H5D_alloc_time_t alloc_time); @@ -476,6 +563,7 @@ class AllocationTime { /// Dataset access property to control chunk cache configuration. /// Do not confuse with the similar file access property for H5Pset_cache +/// \implements PropertyInterface class Caching { public: /// https://support.hdfgroup.org/HDF5/doc/RM/H5P/H5Pset_chunk_cache.html for @@ -498,6 +586,7 @@ class Caching { double _w0; }; +/// \implements PropertyInterface class CreateIntermediateGroup { public: explicit CreateIntermediateGroup(bool create = true); @@ -518,6 +607,7 @@ class CreateIntermediateGroup { }; #ifdef H5_HAVE_PARALLEL +/// \implements PropertyInterface class UseCollectiveIO { public: explicit UseCollectiveIO(bool enable = true); @@ -540,6 +630,7 @@ class UseCollectiveIO { /// creation of this object. This object will not update automatically for later data transfers, /// i.e. `H5Pget_mpio_no_collective_cause` is called in the constructor, and not when fetching /// a value, such as `wasCollective`. +/// \implements PropertyInterface class MpioNoCollectiveCause { public: explicit MpioNoCollectiveCause(const DataTransferProps& dxpl); @@ -575,6 +666,7 @@ struct CreationOrder { /// /// Let user retrieve objects by creation order time instead of name. /// +/// \implements PropertyInterface class LinkCreationOrder { public: /// @@ -599,6 +691,44 @@ class LinkCreationOrder { unsigned _flags; }; + +/// +/// \brief Set threshold for attribute storage. +/// +/// HDF5 can store Attributes in the object header (compact) or in the B-tree +/// (dense). This property sets the threshold when attributes are moved to one +/// or the other storage format. +/// +/// Please refer to the upstream documentation of `H5Pset_attr_phase_change` or +/// Section 8 (Attributes) in the User Guide, in particular Subsection 8.5. +/// +/// \implements PropertyInterface +class AttributePhaseChange { + public: + /// + /// \brief Create the property from the threshold values. + /// + /// When the number of attributes hits `max_compact` the attributes are + /// moved to dense storage, once the number drops to below `min_dense` the + /// attributes are moved to compact storage. + AttributePhaseChange(unsigned max_compact, unsigned min_dense); + + /// \brief Extract threshold values from property list. + explicit AttributePhaseChange(const GroupCreateProps& gcpl); + + unsigned max_compact() const; + unsigned min_dense() const; + + private: + friend GroupCreateProps; + void apply(hid_t hid) const; + + unsigned _max_compact; + unsigned _min_dense; +}; + +/// @} + } // namespace HighFive #include "bits/H5PropertyList_misc.hpp" diff --git a/modules/drivers/highfive/include/highfive/H5Version.hpp b/modules/drivers/highfive/include/highfive/H5Version.hpp new file mode 100644 index 000000000..dc238432c --- /dev/null +++ b/modules/drivers/highfive/include/highfive/H5Version.hpp @@ -0,0 +1,33 @@ +/* + * Copyright (c), 2020 + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ +#pragma once + +#define HIGHFIVE_VERSION_MAJOR 2 +#define HIGHFIVE_VERSION_MINOR 8 +#define HIGHFIVE_VERSION_PATCH 0 + +/** \brief Concatenated representation of the HighFive version. + * + * \warning The macro `HIGHFIVE_VERSION` by itself isn't valid C/C++. + * + * However, it can be stringified with two layers of macros, e.g., + * \code{.cpp} + * #define STRINGIFY_VALUE(s) STRINGIFY_NAME(s) + * #define STRINGIFY_NAME(s) #s + * + * std::cout << STRINGIFY_VALUE(HIGHFIVE_VERSION) << "\n"; + * \endcode + */ +#define HIGHFIVE_VERSION 2.8.0 + +/** \brief String representation of the HighFive version. + * + * \warning This macro only exists from 2.7.1 onwards. + */ +#define HIGHFIVE_VERSION_STRING "2.8.0" diff --git a/modules/drivers/highfive/include/highfive/bits/H5Attribute_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Attribute_misc.hpp index 65cdb2d86..651678829 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Attribute_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Attribute_misc.hpp @@ -61,8 +61,9 @@ inline T Attribute::read() const { template inline void Attribute::read(T& array) const { const DataSpace& mem_space = getMemSpace(); + auto file_datatype = getDataType(); const details::BufferInfo buffer_info( - getDataType(), + file_datatype, [this]() -> std::string { return this->getName(); }, details::BufferInfo::read); @@ -82,37 +83,43 @@ inline void Attribute::read(T& array) const { return; } - auto r = details::data_converter::get_reader(dims, array); - read(r.get_pointer(), buffer_info.data_type); + auto r = details::data_converter::get_reader(dims, array, file_datatype); + read(r.getPointer(), buffer_info.data_type); // re-arrange results - r.unserialize(); - auto t = create_datatype::base_type>(); + r.unserialize(array); + + auto t = buffer_info.data_type; auto c = t.getClass(); + if (c == DataTypeClass::VarLen || t.isVariableStr()) { #if H5_VERSION_GE(1, 12, 0) // This one have been created in 1.12.0 - (void) H5Treclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.get_pointer()); + (void) H5Treclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer()); #else // This one is deprecated since 1.12.0 - (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.get_pointer()); + (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer()); #endif } } template -inline void Attribute::read(T* array, const DataType& dtype) const { +inline void Attribute::read(T* array, const DataType& mem_datatype) const { static_assert(!std::is_const::value, "read() requires a non-const structure to read data into"); - using element_type = typename details::inspector::base_type; - // Auto-detect mem datatype if not provided - const DataType& mem_datatype = dtype.empty() ? create_and_check_datatype() - : dtype; if (H5Aread(getId(), mem_datatype.getId(), static_cast(array)) < 0) { HDF5ErrMapper::ToException("Error during HDF5 Read: "); } } +template +inline void Attribute::read(T* array) const { + using element_type = typename details::inspector::base_type; + const DataType& mem_datatype = create_and_check_datatype(); + + read(array, mem_datatype); +} + template inline void Attribute::write(const T& buffer) { const DataSpace& mem_space = getMemSpace(); @@ -121,8 +128,10 @@ inline void Attribute::write(const T& buffer) { return; } + auto file_datatype = getDataType(); + const details::BufferInfo buffer_info( - getDataType(), + file_datatype, [this]() -> std::string { return this->getName(); }, details::BufferInfo::write); @@ -132,18 +141,23 @@ inline void Attribute::write(const T& buffer) { << " into dataset of dimensions " << mem_space.getNumberDimensions(); throw DataSpaceException(ss.str()); } - auto w = details::data_converter::serialize(buffer); - write_raw(w.get_pointer(), buffer_info.data_type); + auto w = details::data_converter::serialize(buffer, file_datatype); + write_raw(w.getPointer(), buffer_info.data_type); } template -inline void Attribute::write_raw(const T* buffer, const DataType& dtype) { - using element_type = typename details::inspector::base_type; - const auto& mem_datatype = dtype.empty() ? create_and_check_datatype() : dtype; - +inline void Attribute::write_raw(const T* buffer, const DataType& mem_datatype) { if (H5Awrite(getId(), mem_datatype.getId(), buffer) < 0) { HDF5ErrMapper::ToException("Error during HDF5 Write: "); } } +template +inline void Attribute::write_raw(const T* buffer) { + using element_type = typename details::inspector::base_type; + const auto& mem_datatype = create_and_check_datatype(); + + write_raw(buffer, mem_datatype); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/H5Converter_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Converter_misc.hpp index a46f01174..00749d1b6 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Converter_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Converter_misc.hpp @@ -9,899 +9,411 @@ #pragma once #include -#include -#include - -#include "../H5Reference.hpp" -#ifdef H5_USE_BOOST -#include -// starting Boost 1.64, serialization header must come before ublas -#include -#include -#endif -#ifdef H5_USE_EIGEN -#include -#endif + +#include "H5Inspector_misc.hpp" +#include "../H5DataType.hpp" namespace HighFive { namespace details { -inline bool checkDimensions(const std::vector& dims, size_t n_dim_requested) { - size_t n_dim_actual = dims.size(); - - // We should allow reading scalar from shapes like `(1, 1, 1)`. - if (n_dim_requested == 0) { - if (n_dim_actual == 0ul) { - return true; - } - - return size_t(std::count(dims.begin(), dims.end(), 1ul)) == n_dim_actual; - } - - // For non-scalar datasets, we can squeeze away singleton dimension, but - // we never add any. - if (n_dim_actual < n_dim_requested) { - return false; - } - - // Special case for 1-dimensional arrays, which can squeeze `1`s from either - // side simultaneously if needed. - if (n_dim_requested == 1ul) { - return n_dim_actual >= 1ul && - size_t(std::count(dims.begin(), dims.end(), 1ul)) >= n_dim_actual - 1ul; - } - - // All other cases strip front only. This avoid unstable behaviour when - // squeezing singleton dimensions. - size_t n_dim_excess = n_dim_actual - n_dim_requested; - - bool squeeze_back = true; - for (size_t i = 1; i <= n_dim_excess; ++i) { - if (dims[n_dim_actual - i] != 1) { - squeeze_back = false; - break; - } - } - - return squeeze_back; -} - - -inline std::vector squeezeDimensions(const std::vector& dims, - size_t n_dim_requested) { - auto format_error_message = [&]() -> std::string { - return "Can't interpret dims = " + format_vector(dims) + " as " + - std::to_string(n_dim_requested) + "-dimensional."; - }; - - if (n_dim_requested == 0) { - if (!checkDimensions(dims, n_dim_requested)) { - throw std::invalid_argument(format_error_message()); - } - - return {1ul}; - } - - auto n_dim = dims.size(); - if (n_dim < n_dim_requested) { - throw std::invalid_argument(format_error_message()); - } - - if (n_dim_requested == 1ul) { - size_t non_singleton_dim = size_t(-1); - for (size_t i = 0; i < n_dim; ++i) { - if (dims[i] != 1ul) { - if (non_singleton_dim == size_t(-1)) { - non_singleton_dim = i; - } else { - throw std::invalid_argument(format_error_message()); - } - } - } - - return {dims[std::min(non_singleton_dim, n_dim - 1)]}; - } - - size_t n_dim_excess = dims.size() - n_dim_requested; - for (size_t i = 1; i <= n_dim_excess; ++i) { - if (dims[n_dim - i] != 1) { - throw std::invalid_argument(format_error_message()); - } - } - - return std::vector(dims.begin(), - dims.end() - static_cast(n_dim_excess)); -} -} // namespace details +template +struct is_std_string { + static constexpr bool value = + std::is_same::base_type, std::string>::value; +}; +template +struct enable_shallow_copy + : public std::enable_if::value && inspector::is_trivially_copyable, V> {}; -inline size_t compute_total_size(const std::vector& dims) { - return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies()); -} +template +struct enable_deep_copy + : public std::enable_if::value && !inspector::is_trivially_copyable, V> {}; -template -using unqualified_t = typename std::remove_const::type>::type; - -/***** -inspector { - using type = T - // base_type is the base type inside c++ (e.g. std::vector => int) - using base_type - // hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector => const char*) - using hdf5_type - - // Number of dimensions starting from here - static constexpr size_t recursive_ndim - // Is the inner type trivially copyable for optimisation - // If this value is true: data() is mandatory - // If this value is false: getSizeVal, getSize, serialize, unserialize are mandatory - static constexpr bool is_trivially_copyable - - // Reading: - // Allocate the value following dims (should be recursive) - static void prepare(type& val, const std::vector dims) - // Return the size of the vector pass to/from hdf5 from a vector of dims - static size_t getSize(const std::vector& dims) - // Return a pointer of the first value of val (for reading) - static hdf5_type* data(type& val) - // Take a serialized vector 'in', some dims and copy value to val (for reading) - static void unserialize(const hdf5_type* in, const std::vector&i, type& val) - - - // Writing: - // Return the size of the vector pass to/from hdf5 from a value - static size_t getSizeVal(const type& val) - // Return a point of the first value of val - static const hdf5_type* data(const type& val) - // Take a val and serialize it inside 'out' - static void serialize(const type& val, hdf5_type* out) - // Return an array of dimensions of the space needed for writing val - static std::vector getDimensions(const type& val) -} -*****/ +template +struct enable_string_copy: public std::enable_if::value, V> {}; -namespace details { -template -struct type_helper { +template +struct ShallowCopyBuffer { using type = unqualified_t; - using base_type = unqualified_t; - using hdf5_type = base_type; - - static constexpr size_t ndim = 0; - static constexpr size_t recursive_ndim = ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value; - - static std::vector getDimensions(const type& /* val */) { - return {}; - } - - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } + using hdf5_type = + typename std::conditional::hdf5_type>::type, + typename inspector::hdf5_type>::type; - static void prepare(type& /* val */, const std::vector& /* dims */) {} + ShallowCopyBuffer() = delete; - static hdf5_type* data(type& val) { - static_assert(is_trivially_copyable, "The type is not trivially copyable"); - return &val; - } + explicit ShallowCopyBuffer(typename std::conditional::type val) + : ptr(inspector::data(val)){}; - static const hdf5_type* data(const type& val) { - static_assert(is_trivially_copyable, "The type is not trivially copyable"); - return &val; + hdf5_type* getPointer() const { + return ptr; } - static void serialize(const type& val, hdf5_type* m) { - static_assert(is_trivially_copyable, "The type is not trivially copyable"); - *m = val; + hdf5_type* begin() const { + return getPointer(); } - static void unserialize(const hdf5_type* vec, - const std::vector& /* dims */, - type& val) { - static_assert(is_trivially_copyable, "The type is not trivially copyable"); - val = vec[0]; + void unserialize(T& /* val */) const { + /* nothing to do. */ } -}; -template -struct inspector: type_helper {}; - -enum class Boolean : int8_t { - HighFiveFalse = 0, - HighFiveTrue = 1, + private: + hdf5_type* ptr; }; -template <> -struct inspector: type_helper { - using base_type = Boolean; - using hdf5_type = int8_t; - - static constexpr bool is_trivially_copyable = false; - - static hdf5_type* data(type& /* val */) { - throw DataSpaceException("A boolean cannot be read directly."); - } +template +struct DeepCopyBuffer { + using type = unqualified_t; + using hdf5_type = typename inspector::hdf5_type; - static const hdf5_type* data(const type& /* val */) { - throw DataSpaceException("A boolean cannot be written directly."); - } + explicit DeepCopyBuffer(const std::vector& _dims) + : buffer(inspector::getSize(_dims)) + , dims(_dims) {} - static void unserialize(const hdf5_type* vec, - const std::vector& /* dims */, - type& val) { - val = vec[0] != 0 ? true : false; + hdf5_type* getPointer() { + return buffer.data(); } - static void serialize(const type& val, hdf5_type* m) { - *m = val ? 1 : 0; + hdf5_type const* getPointer() const { + return buffer.data(); } -}; - -template <> -struct inspector: type_helper { - using hdf5_type = const char*; - static hdf5_type* data(type& /* val */) { - throw DataSpaceException("A std::string cannot be read directly."); + hdf5_type* begin() { + return getPointer(); } - static const hdf5_type* data(const type& /* val */) { - throw DataSpaceException("A std::string cannot be written directly."); + hdf5_type const* begin() const { + return getPointer(); } - static void serialize(const type& val, hdf5_type* m) { - *m = val.c_str(); + void unserialize(T& val) const { + inspector::unserialize(buffer.data(), dims, val); } - static void unserialize(const hdf5_type* vec, - const std::vector& /* dims */, - type& val) { - val = vec[0]; - } + private: + std::vector buffer; + std::vector dims; }; -template <> -struct inspector: type_helper { - using hdf5_type = hobj_ref_t; +enum class BufferMode { Read, Write }; - static constexpr bool is_trivially_copyable = false; - static hdf5_type* data(type& /* val */) { - throw DataSpaceException("A Reference cannot be read directly."); - } - - static const hdf5_type* data(const type& /* val */) { - throw DataSpaceException("A Reference cannot be written directly."); - } - - static void serialize(const type& val, hdf5_type* m) { - hobj_ref_t ref; - val.create_ref(&ref); - *m = ref; - } - - static void unserialize(const hdf5_type* vec, - const std::vector& /* dims */, - type& val) { - val = type{vec[0]}; +/// +/// \brief String length in bytes excluding the `\0`. +/// +inline size_t char_buffer_size(char const* const str, size_t max_string_length) { + for (size_t i = 0; i <= max_string_length; ++i) { + if (str[i] == '\0') { + return i; + } } -}; - -template -struct inspector> { - using type = FixedLenStringArray; - using value_type = char*; - using base_type = FixedLenStringArray; - using hdf5_type = char; - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim; - static constexpr bool is_trivially_copyable = false; + return max_string_length; +} - static std::vector getDimensions(const type& val) { - return std::vector{val.size()}; - } - static size_t getSizeVal(const type& val) { - return N * compute_total_size(getDimensions(val)); - } +/// +/// \brief A buffer for reading/writing strings. +/// +/// A string in HDF5 can be represented as a fixed or variable length string. +/// The important difference for this buffer is that `H5D{read,write}` expects +/// different input depending on whether the strings are fixed or variable length. +/// For fixed length strings, it expects an array of chars, i.e. one string +/// packed after the other contiguously. While for variable length strings it +/// expects a list of pointers to the beginning of each string. Variable length +/// string must be null-terminated; because that's how their length is +/// determined. +/// +/// This buffer hides the difference between fixed and variable length strings +/// by having internal data structures available for both cases at compile time. +/// The choice which internal buffer to use is made at runtime. +/// +/// Consider an HDF5 dataset with N fixed-length strings, each of which is M +/// characters long. Then the in-memory strings are copied into an internal +/// buffer of size N*M. If null- or space-padded the buffer should be filled +/// with the appropriate character. This is important if the in-memory strings +/// are less than M characters long. +/// +/// An HDF5 dataset with N variable-length strings (all null-terminated) uses +/// the internal list of pointers to the beginning of each string. Those +/// pointers can either point to the in-memory strings themselves, if those +/// strings are known to be null-terminated. Otherwise the in-memory strings are +/// copied to an internal buffer of null-terminated strings; and the pointer +/// points to the start of the string in the internal buffer. +/// +/// This class is responsible for arranging the strings properly before passing +/// the buffers to HDF5. To keep this class generic, it provides a generic +/// read/write interface to the internal strings, i.e. a pointer with a size. +/// For reading from the buffer the proxy is called `StringConstView`. This +/// proxy object is to be used by the `inspector` to copy from the buffer into +/// the final destination, e.g. an `std::string`. Similarly, there's a proxy +/// object for serializing into the buffer, i.e. the `StringView`. Again the +/// `inspector` is responsible for obtaining the pointer, size and padding of +/// the string. +/// +/// Nomenclature: +/// - size of a string is the number of bytes required to store the string, +/// including the null character for null-terminated strings. +/// +/// - length of a string is the number of bytes without the null character. +/// +/// Note: both 'length' and 'size' are counted in number of bytes, not number +/// of symbols or characters. Even for UTF8 strings. +template +struct StringBuffer { + using type = unqualified_t; + using hdf5_type = typename inspector::hdf5_type; - static size_t getSize(const std::vector& dims) { - return N * compute_total_size(dims); - } + class StringView { + public: + StringView(StringBuffer& _buffer, size_t _i) + : buffer(_buffer) + , i(_i) {} + + /// + /// \brief Assign the in-memory string to the buffer. + /// + /// This method copies the in-memory string to the appropriate + /// internal buffer as needed. + /// + /// The `length` is the length of the string in bytes. + void assign(char const* data, size_t length, StringPadding padding) { + if (buffer.isVariableLengthString()) { + if (padding == StringPadding::NullTerminated) { + buffer.variable_length_pointers[i] = data; + } else { + buffer.variable_length_buffer[i] = std::string(data, length); + buffer.variable_length_pointers[i] = buffer.variable_length_buffer[i].data(); + } + } else if (buffer.isFixedLengthString()) { + // If the buffer is fixed-length and null-terminated, then + // `buffer.string_length` doesn't include the null-character. + if (length > buffer.string_length) { + throw std::invalid_argument("String length too big."); + } - static void prepare(type& /* val */, const std::vector& dims) { - if (dims[0] > N) { - std::ostringstream os; - os << "Size of FixedlenStringArray (" << N << ") is too small for dims (" << dims[0] - << ")."; - throw DataSpaceException(os.str()); + memcpy(&buffer.fixed_length_buffer[i * buffer.string_size], data, length); + } } - } - static hdf5_type* data(type& val) { - return val.data(); - } + private: + StringBuffer& buffer; + size_t i; + }; - static const hdf5_type* data(const type& val) { - return val.data(); - } - static void serialize(const type& val, hdf5_type* m) { - for (size_t i = 0; i < val.size(); ++i) { - std::memcpy(m + i * N, val[i], N); + class StringConstView { + public: + StringConstView(const StringBuffer& _buffer, size_t _i) + : buffer(_buffer) + , i(_i) {} + + /// \brief Pointer to the first byte of the string. + /// + /// The valid indices for this pointer are: 0, ..., length() - 1. + char const* data() const { + if (buffer.isVariableLengthString()) { + return buffer.variable_length_pointers[i]; + } else { + return &buffer.fixed_length_buffer[i * buffer.string_size]; + } } - } - static void unserialize(const hdf5_type* vec, const std::vector& dims, type& val) { - for (size_t i = 0; i < dims[0]; ++i) { - std::array s; - std::memcpy(s.data(), vec + (i * N), N); - val.push_back(s); + /// \brief Length of the string in bytes. + /// + /// Note that for null-terminated strings the "length" doesn't include + /// the null character. Hence, if storing this string as a + /// null-terminated string, the destination buffer needs to be at least + /// `length() + 1` bytes long. + size_t length() const { + if (buffer.isNullTerminated()) { + return char_buffer_size(data(), buffer.string_length); + } else { + return buffer.string_length; + } } - } -}; -template -struct inspector> { - using type = std::vector; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static std::vector getDimensions(const type& val) { - std::vector sizes(recursive_ndim, 1ul); - sizes[0] = val.size(); - if (!val.empty()) { - auto s = inspector::getDimensions(val[0]); - std::copy(s.begin(), s.end(), sizes.begin() + 1); - } - return sizes; - } + private: + const StringBuffer& buffer; + size_t i; + }; - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } + class Iterator { + public: + Iterator(StringBuffer& _buffer, size_t _pos) + : buffer(_buffer) + , pos(_pos) {} - static void prepare(type& val, const std::vector& dims) { - val.resize(dims[0]); - std::vector next_dims(dims.begin() + 1, dims.end()); - for (auto&& e: val) { - inspector::prepare(e, next_dims); + Iterator operator+(size_t n_strings) const { + return Iterator(buffer, pos + n_strings); } - } - static hdf5_type* data(type& val) { - return inspector::data(val[0]); - } - - static const hdf5_type* data(const type& val) { - return inspector::data(val[0]); - } - - static void serialize(const type& val, hdf5_type* m) { - size_t subsize = inspector::getSizeVal(val[0]); - for (auto&& e: val) { - inspector::serialize(e, m); - m += subsize; + void operator+=(size_t n_strings) { + pos += n_strings; } - } - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - std::vector next_dims(dims.begin() + 1, dims.end()); - size_t next_size = compute_total_size(next_dims); - for (size_t i = 0; i < dims[0]; ++i) { - inspector::unserialize(vec_align + i * next_size, next_dims, val[i]); + StringView operator*() { + return StringView(buffer, pos); } - } -}; -template <> -struct inspector> { - using type = std::vector; - using value_type = bool; - using base_type = Boolean; - using hdf5_type = uint8_t; - - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim; - static constexpr bool is_trivially_copyable = false; - - static std::vector getDimensions(const type& val) { - std::vector sizes{val.size()}; - return sizes; - } - - static size_t getSizeVal(const type& val) { - return val.size(); - } - - static size_t getSize(const std::vector& dims) { - if (dims.size() > 1) { - throw DataSpaceException("std::vector is only 1 dimension."); + StringConstView operator*() const { + return StringConstView(buffer, pos); } - return dims[0]; - } - static void prepare(type& val, const std::vector& dims) { - if (dims.size() > 1) { - throw DataSpaceException("std::vector is only 1 dimension."); - } - val.resize(dims[0]); - } - - static hdf5_type* data(type& /* val */) { - throw DataSpaceException("A std::vector cannot be read directly."); - } - - static const hdf5_type* data(const type& /* val */) { - throw DataSpaceException("A std::vector cannot be written directly."); - } + private: + StringBuffer& buffer; + size_t pos; + }; - static void serialize(const type& val, hdf5_type* m) { - for (size_t i = 0; i < val.size(); ++i) { - m[i] = val[i] ? 1 : 0; + StringBuffer(std::vector _dims, const DataType& _file_datatype) + : file_datatype(_file_datatype.asStringType()) + , padding(file_datatype.getPadding()) + , string_size(file_datatype.isVariableStr() ? size_t(-1) : file_datatype.getSize()) + , string_length(string_size - size_t(isNullTerminated())) + , dims(_dims) { + if (string_size == 0 && isNullTerminated()) { + throw DataTypeException( + "Fixed-length, null-terminated need at least one byte to store the " + "null-character."); + } + + auto n_strings = compute_total_size(dims); + if (isVariableLengthString()) { + variable_length_buffer.resize(n_strings); + variable_length_pointers.resize(n_strings); + } else { + char pad = padding == StringPadding::SpacePadded ? ' ' : '\0'; + fixed_length_buffer.assign(n_strings * string_size, pad); } } - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - for (size_t i = 0; i < dims[0]; ++i) { - val[i] = vec_align[i] != 0 ? true : false; - } + bool isVariableLengthString() const { + return file_datatype.isVariableStr(); } -}; -template -struct inspector> { - using type = std::array; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static std::vector getDimensions(const type& val) { - std::vector sizes{N}; - if (!val.empty()) { - auto s = inspector::getDimensions(val[0]); - sizes.insert(sizes.end(), s.begin(), s.end()); - } - return sizes; + bool isFixedLengthString() const { + return file_datatype.isFixedLenStr(); } - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); + bool isNullTerminated() const { + return file_datatype.getPadding() == StringPadding::NullTerminated; } - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } - static void prepare(type& /* val */, const std::vector& dims) { - if (dims[0] > N) { - std::ostringstream os; - os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ")."; - throw DataSpaceException(os.str()); + void* getPointer() { + if (file_datatype.isVariableStr()) { + return variable_length_pointers.data(); + } else { + return fixed_length_buffer.data(); } } - static hdf5_type* data(type& val) { - return inspector::data(val[0]); + Iterator begin() { + return Iterator(*this, 0ul); } - static const hdf5_type* data(const type& val) { - return inspector::data(val[0]); + void unserialize(T& val) { + inspector::unserialize(begin(), dims, val); } - static void serialize(const type& val, hdf5_type* m) { - size_t subsize = inspector::getSizeVal(val[0]); - for (auto& e: val) { - inspector::serialize(e, m); - m += subsize; - } - } + private: + StringType file_datatype; + StringPadding padding; + size_t string_size; // Size of buffer required to store the string. + // Meaningful for fixed length strings only. + size_t string_length; // Semantic length of string. + std::vector dims; - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - if (dims[0] != N) { - std::ostringstream os; - os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with " - << N << " elements."; - throw DataSpaceException(os.str()); - } - std::vector next_dims(dims.begin() + 1, dims.end()); - size_t next_size = compute_total_size(next_dims); - for (size_t i = 0; i < dims[0]; ++i) { - inspector::unserialize(vec_align + i * next_size, next_dims, val[i]); - } - } + std::vector fixed_length_buffer; + std::vector variable_length_buffer; + std::vector< + typename std::conditional::type*> + variable_length_pointers; }; -// Cannot be use for reading -template -struct inspector { - using type = T*; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static size_t getSizeVal(const type& /* val */) { - throw DataSpaceException("Not possible to have size of a T*"); - } - static std::vector getDimensions(const type& /* val */) { - throw DataSpaceException("Not possible to have size of a T*"); - } +template +struct Writer; - static const hdf5_type* data(const type& val) { - return reinterpret_cast(val); - } +template +struct Writer::type>: public ShallowCopyBuffer { + private: + using super = ShallowCopyBuffer; - /* it works because there is only T[][][] currently - we will fix it one day */ - static void serialize(const type& /* val */, hdf5_type* /* m */) { - throw DataSpaceException("Not possible to serialize a T*"); - } + public: + explicit Writer(const T& val, const DataType& /* file_datatype */) + : super(val){}; }; -// Cannot be use for reading -template -struct inspector { - using type = T[N]; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 1; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - - static std::vector getDimensions(const type& val) { - std::vector sizes{N}; - if (N > 0) { - auto s = inspector::getDimensions(val[0]); - sizes.insert(sizes.end(), s.begin(), s.end()); - } - return sizes; - } - - static const hdf5_type* data(const type& val) { - return inspector::data(val[0]); - } - - /* it works because there is only T[][][] currently - we will fix it one day */ - static void serialize(const type& val, hdf5_type* m) { - size_t subsize = inspector::getSizeVal(val[0]); - for (size_t i = 0; i < N; ++i) { - inspector::serialize(val[i], m + i * subsize); - } +template +struct Writer::type>: public DeepCopyBuffer { + explicit Writer(const T& val, const DataType& /* file_datatype */) + : DeepCopyBuffer(inspector::getDimensions(val)) { + inspector::serialize(val, this->begin()); } }; -#ifdef H5_USE_EIGEN -template -struct inspector> { - using type = Eigen::Matrix; - using value_type = T; - using base_type = typename inspector::base_type; - using hdf5_type = base_type; - - static constexpr size_t ndim = 2; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static std::vector getDimensions(const type& val) { - std::vector sizes{static_cast(val.rows()), static_cast(val.cols())}; - auto s = inspector::getDimensions(val.data()[0]); - sizes.insert(sizes.end(), s.begin(), s.end()); - return sizes; - } - - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } - - static void prepare(type& val, const std::vector& dims) { - if (dims[0] != static_cast(val.rows()) || - dims[1] != static_cast(val.cols())) { - val.resize(static_cast(dims[0]), - static_cast(dims[1])); - } - } - - static hdf5_type* data(type& val) { - return inspector::data(*val.data()); - } - - static const hdf5_type* data(const type& val) { - return inspector::data(*val.data()); - } - - static void serialize(const type& val, hdf5_type* m) { - std::memcpy(m, val.data(), static_cast(val.size()) * sizeof(hdf5_type)); - } - - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - if (dims.size() < 2) { - std::ostringstream os; - os << "Impossible to pair DataSet with " << dims.size() - << " dimensions into an eigen-matrix."; - throw DataSpaceException(os.str()); - } - std::memcpy(val.data(), vec_align, compute_total_size(dims) * sizeof(hdf5_type)); +template +struct Writer::type>: public StringBuffer { + explicit Writer(const T& val, const DataType& _file_datatype) + : StringBuffer(inspector::getDimensions(val), _file_datatype) { + inspector::serialize(val, this->begin()); } }; -#endif - -#ifdef H5_USE_BOOST -template -struct inspector> { - using type = boost::multi_array; - using value_type = T; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = Dims; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static std::vector getDimensions(const type& val) { - std::vector sizes; - for (size_t i = 0; i < ndim; ++i) { - sizes.push_back(val.shape()[i]); - } - auto s = inspector::getDimensions(val.data()[0]); - sizes.insert(sizes.end(), s.begin(), s.end()); - return sizes; - } - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } - - static void prepare(type& val, const std::vector& dims) { - if (dims.size() < ndim) { - std::ostringstream os; - os << "Only '" << dims.size() << "' given but boost::multi_array is of size '" << ndim - << "'."; - throw DataSpaceException(os.str()); - } - boost::array ext; - std::copy(dims.begin(), dims.begin() + ndim, ext.begin()); - val.resize(ext); - std::vector next_dims(dims.begin() + Dims, dims.end()); - std::size_t size = std::accumulate(dims.begin(), - dims.begin() + Dims, - std::size_t{1}, - std::multiplies()); - for (size_t i = 0; i < size; ++i) { - inspector::prepare(*(val.origin() + i), next_dims); - } - } - - static hdf5_type* data(type& val) { - return inspector::data(*val.data()); - } - - static const hdf5_type* data(const type& val) { - return inspector::data(*val.data()); - } - - static void serialize(const type& val, hdf5_type* m) { - size_t size = val.num_elements(); - size_t subsize = inspector::getSizeVal(*val.origin()); - for (size_t i = 0; i < size; ++i) { - inspector::serialize(*(val.origin() + i), m + i * subsize); - } - } - - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - std::vector next_dims(dims.begin() + ndim, dims.end()); - size_t subsize = compute_total_size(next_dims); - for (size_t i = 0; i < val.num_elements(); ++i) { - inspector::unserialize(vec_align + i * subsize, - next_dims, - *(val.origin() + i)); - } - } -}; +template +struct Reader; template -struct inspector> { - using type = boost::numeric::ublas::matrix; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 2; - static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_copyable; - - static std::vector getDimensions(const type& val) { - std::vector sizes{val.size1(), val.size2()}; - auto s = inspector::getDimensions(val(0, 0)); - sizes.insert(sizes.end(), s.begin(), s.end()); - return sizes; - } - - static size_t getSizeVal(const type& val) { - return compute_total_size(getDimensions(val)); - } - - static size_t getSize(const std::vector& dims) { - return compute_total_size(dims); - } - - static void prepare(type& val, const std::vector& dims) { - if (dims.size() < ndim) { - std::ostringstream os; - os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim - << " boost::numeric::ublas::matrix"; - throw DataSpaceException(os.str()); - } - val.resize(dims[0], dims[1], false); - } - - static hdf5_type* data(type& val) { - return inspector::data(val(0, 0)); - } - - static const hdf5_type* data(const type& val) { - return inspector::data(val(0, 0)); - } - - static void serialize(const type& val, hdf5_type* m) { - size_t size = val.size1() * val.size2(); - size_t subsize = inspector::getSizeVal(val(0, 0)); - for (size_t i = 0; i < size; ++i) { - inspector::serialize(*(&val(0, 0) + i), m + i * subsize); - } - } - - static void unserialize(const hdf5_type* vec_align, - const std::vector& dims, - type& val) { - std::vector next_dims(dims.begin() + ndim, dims.end()); - size_t subsize = compute_total_size(next_dims); - size_t size = val.size1() * val.size2(); - for (size_t i = 0; i < size; ++i) { - inspector::unserialize(vec_align + i * subsize, - next_dims, - *(&val(0, 0) + i)); - } - } +struct Reader::type>: public ShallowCopyBuffer { + private: + using super = ShallowCopyBuffer; + using type = typename super::type; + + public: + Reader(const std::vector&, type& val, const DataType& /* file_datatype */) + : super(val) {} }; -#endif template -struct Writer { - using hdf5_type = typename inspector::hdf5_type; - const hdf5_type* get_pointer() { - if (vec.empty()) { - return ptr; - } else { - return vec.data(); - } - } - std::vector vec{}; - const hdf5_type* ptr{nullptr}; +struct Reader::type>: public DeepCopyBuffer { + private: + using super = DeepCopyBuffer; + using type = typename super::type; + + public: + Reader(const std::vector& _dims, type&, const DataType& /* file_datatype */) + : super(_dims) {} }; -template -struct Reader { - using type = unqualified_t; - using hdf5_type = typename inspector::hdf5_type; - - Reader(const std::vector& _dims, type& _val) - : dims(_dims) - , val(_val) {} - hdf5_type* get_pointer() { - if (vec.empty()) { - return inspector::data(val); - } else { - return vec.data(); - } - } - - void unserialize() { - if (!vec.empty()) { - inspector::unserialize(vec.data(), dims, val); - } - } - - std::vector dims{}; - std::vector vec{}; - type& val{}; +template +struct Reader::type>: public StringBuffer { + public: + explicit Reader(const std::vector& _dims, + const T& /* val */, + const DataType& _file_datatype) + : StringBuffer(_dims, _file_datatype) {} }; struct data_converter { template - static typename std::enable_if::is_trivially_copyable, Writer>::type serialize( - const typename inspector::type& val) { - Writer w; - w.ptr = inspector::data(val); - return w; + static Writer serialize(const typename inspector::type& val, + const DataType& file_datatype) { + return Writer(val, file_datatype); } template - static typename std::enable_if::is_trivially_copyable, Writer>::type serialize( - const typename inspector::type& val) { - Writer w; - w.vec.resize(inspector::getSizeVal(val)); - inspector::serialize(val, w.vec.data()); - return w; - } - - template - static - typename std::enable_if>::is_trivially_copyable, Reader>::type - get_reader(const std::vector& dims, T& val) { - auto effective_dims = details::squeezeDimensions(dims, inspector::recursive_ndim); - Reader r(effective_dims, val); - inspector::prepare(r.val, effective_dims); - return r; - } - - template - static typename std::enable_if>::is_trivially_copyable, - Reader>::type - get_reader(const std::vector& dims, T& val) { + static Reader get_reader(const std::vector& dims, + T& val, + const DataType& file_datatype) { + // TODO Use bufferinfo for recursive_ndim auto effective_dims = details::squeezeDimensions(dims, inspector::recursive_ndim); - - Reader r(effective_dims, val); - inspector::prepare(r.val, effective_dims); - r.vec.resize(inspector::getSize(effective_dims)); - return r; + inspector::prepare(val, effective_dims); + return Reader(effective_dims, val, file_datatype); } }; diff --git a/modules/drivers/highfive/include/highfive/bits/H5DataType_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5DataType_misc.hpp index afe200c80..8535d617a 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5DataType_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5DataType_misc.hpp @@ -22,10 +22,68 @@ #include #endif -#include "H5Converter_misc.hpp" +#include "H5Inspector_misc.hpp" namespace HighFive { +namespace detail { + +inline hid_t h5t_copy(hid_t original) { + auto copy = H5Tcopy(original); + if (copy == H5I_INVALID_HID) { + HDF5ErrMapper::ToException("Error copying datatype."); + } + + return copy; +} + +inline hsize_t h5t_get_size(hid_t hid) { + hsize_t size = H5Tget_size(hid); + if (size == 0) { + HDF5ErrMapper::ToException("Error getting size of datatype."); + } + + return size; +} + +inline H5T_cset_t h5t_get_cset(hid_t hid) { + auto cset = H5Tget_cset(hid); + if (cset == H5T_CSET_ERROR) { + HDF5ErrMapper::ToException("Error getting cset of datatype."); + } + + return cset; +} + +inline H5T_str_t h5t_get_strpad(hid_t hid) { + auto strpad = H5Tget_strpad(hid); + if (strpad == H5T_STR_ERROR) { + HDF5ErrMapper::ToException("Error getting strpad of datatype."); + } + + return strpad; +} + +inline void h5t_set_size(hid_t hid, hsize_t size) { + if (H5Tset_size(hid, size) < 0) { + HDF5ErrMapper::ToException("Error setting size of datatype."); + } +} + +inline void h5t_set_cset(hid_t hid, H5T_cset_t cset) { + if (H5Tset_cset(hid, cset) < 0) { + HDF5ErrMapper::ToException("Error setting cset of datatype."); + } +} + +inline void h5t_set_strpad(hid_t hid, H5T_str_t strpad) { + if (H5Tset_strpad(hid, strpad) < 0) { + HDF5ErrMapper::ToException("Error setting strpad of datatype."); + } +} +} // namespace detail + + namespace { // unnamed inline DataTypeClass convert_type_class(const H5T_class_t& tclass); inline std::string type_class_string(DataTypeClass); @@ -41,7 +99,7 @@ inline DataTypeClass DataType::getClass() const { } inline size_t DataType::getSize() const { - return H5Tget_size(_hid); + return detail::h5t_get_size(_hid); } inline bool DataType::operator==(const DataType& other) const { @@ -68,68 +126,110 @@ inline bool DataType::isReference() const { return H5Tequal(_hid, H5T_STD_REF_OBJ) > 0; } +inline StringType DataType::asStringType() const { + if (getClass() != DataTypeClass::String) { + throw DataTypeException("Invalid conversion to StringType."); + } + + if (isValid() && H5Iinc_ref(_hid) < 0) { + throw ObjectException("Reference counter increase failure"); + } + + return StringType(_hid); +} + inline std::string DataType::string() const { return type_class_string(getClass()) + std::to_string(getSize() * 8); } +inline StringPadding StringType::getPadding() const { + return StringPadding(detail::h5t_get_strpad(_hid)); +} + +inline CharacterSet StringType::getCharacterSet() const { + return CharacterSet(detail::h5t_get_cset(_hid)); +} + +inline FixedLengthStringType::FixedLengthStringType(size_t size, + StringPadding padding, + CharacterSet character_set) { + if (size == 0 && padding == StringPadding::NullTerminated) { + throw DataTypeException( + "Fixed-length, null-terminated need at least one byte to store the null-character."); + } + + _hid = detail::h5t_copy(H5T_C_S1); + + detail::h5t_set_size(_hid, hsize_t(size)); + detail::h5t_set_cset(_hid, H5T_cset_t(character_set)); + detail::h5t_set_strpad(_hid, H5T_str_t(padding)); +} + +inline VariableLengthStringType::VariableLengthStringType(CharacterSet character_set) { + _hid = detail::h5t_copy(H5T_C_S1); + + detail::h5t_set_size(_hid, H5T_VARIABLE); + detail::h5t_set_cset(_hid, H5T_cset_t(character_set)); +} + // char mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_CHAR); + _hid = detail::h5t_copy(H5T_NATIVE_CHAR); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_SCHAR); + _hid = detail::h5t_copy(H5T_NATIVE_SCHAR); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_UCHAR); + _hid = detail::h5t_copy(H5T_NATIVE_UCHAR); } // short mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_SHORT); + _hid = detail::h5t_copy(H5T_NATIVE_SHORT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_USHORT); + _hid = detail::h5t_copy(H5T_NATIVE_USHORT); } // integer mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_INT); + _hid = detail::h5t_copy(H5T_NATIVE_INT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_UINT); + _hid = detail::h5t_copy(H5T_NATIVE_UINT); } // long mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LONG); + _hid = detail::h5t_copy(H5T_NATIVE_LONG); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_ULONG); + _hid = detail::h5t_copy(H5T_NATIVE_ULONG); } // long long mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LLONG); + _hid = detail::h5t_copy(H5T_NATIVE_LLONG); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_ULLONG); + _hid = detail::h5t_copy(H5T_NATIVE_ULLONG); } // half-float, float, double and long double mapping @@ -138,11 +238,11 @@ using float16_t = half_float::half; template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_FLOAT); + _hid = detail::h5t_copy(H5T_NATIVE_FLOAT); // Sign position, exponent position, exponent size, mantissa position, mantissa size H5Tset_fields(_hid, 15, 10, 5, 0, 10); // Total datatype size (in bytes) - H5Tset_size(_hid, 2); + detail::h5t_set_size(_hid, 2); // Floating point exponent bias H5Tset_ebias(_hid, 15); } @@ -150,17 +250,17 @@ inline AtomicType::AtomicType() { template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_FLOAT); + _hid = detail::h5t_copy(H5T_NATIVE_FLOAT); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_DOUBLE); + _hid = detail::h5t_copy(H5T_NATIVE_DOUBLE); } template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_LDOUBLE); + _hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE); } // std string @@ -173,7 +273,7 @@ inline AtomicType::AtomicType() { // std byte template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_NATIVE_B8); + _hid = detail::h5t_copy(H5T_NATIVE_B8); } #endif @@ -200,8 +300,8 @@ class AtomicType>: public DataType { : DataType( CompoundType({{"r", create_datatype(), 0}, {"i", create_datatype(), sizeof(T)}}, sizeof(std::complex))) { - static_assert(std::is_floating_point::value, - "std::complex accepts only floating point numbers."); + static_assert(std::is_arithmetic::value, + "std::complex accepts only floating point and integral numbers."); } }; @@ -230,18 +330,15 @@ inline FixedLenStringArray::FixedLenStringArray(const char array[][N], std::s template inline FixedLenStringArray::FixedLenStringArray(const std::string* iter_begin, const std::string* iter_end) { - datavec.resize(static_cast(iter_end - iter_begin)); - for (auto& dst_array: datavec) { - const char* src = (iter_begin++)->c_str(); - const size_t length = std::min(N - 1, std::strlen(src)); - std::memcpy(dst_array.data(), src, length); - dst_array[length] = 0; + datavec.reserve(static_cast(iter_end - iter_begin)); + for (std::string const* it = iter_begin; it != iter_end; ++it) { + push_back(*it); } } template inline FixedLenStringArray::FixedLenStringArray(const std::vector& vec) - : FixedLenStringArray(&vec.front(), &vec.back()) {} + : FixedLenStringArray(vec.data(), vec.data() + vec.size()) {} template inline FixedLenStringArray::FixedLenStringArray( @@ -271,7 +368,7 @@ inline std::string FixedLenStringArray::getString(std::size_t i) const { // Reference mapping template <> inline AtomicType::AtomicType() { - _hid = H5Tcopy(H5T_STD_REF_OBJ); + _hid = detail::h5t_copy(H5T_STD_REF_OBJ); } inline size_t find_first_atomic_member_size(hid_t hid) { @@ -294,7 +391,7 @@ inline size_t find_first_atomic_member_size(hid_t hid) { } else if (H5Tget_class(hid) == H5T_STRING) { return 1; } - return H5Tget_size(hid); + return detail::h5t_get_size(hid); } // Calculate the padding required to align an element of a struct @@ -325,7 +422,7 @@ inline void CompoundType::create(size_t size) { // Do a first pass to find the total size of the compound datatype for (auto& member: members) { - size_t member_size = H5Tget_size(member.base_type.getId()); + size_t member_size = detail::h5t_get_size(member.base_type.getId()); if (member_size == 0) { throw DataTypeException("Cannot get size of DataType with hid: " + @@ -393,12 +490,9 @@ inline void EnumType::commit(const Object& object, const std::string& name) c namespace { inline hid_t create_string(size_t length) { - hid_t _hid = H5Tcopy(H5T_C_S1); - if (H5Tset_size(_hid, length) < 0) { - HDF5ErrMapper::ToException("Unable to define datatype size to variable"); - } - // define encoding to UTF-8 by default - H5Tset_cset(_hid, H5T_CSET_UTF8); + hid_t _hid = detail::h5t_copy(H5T_C_S1); + detail::h5t_set_size(_hid, length); + detail::h5t_set_cset(_hid, H5T_CSET_UTF8); return _hid; } diff --git a/modules/drivers/highfive/include/highfive/bits/H5Dataspace_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Dataspace_misc.hpp index a72054ad2..0fdcacefd 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Dataspace_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Dataspace_misc.hpp @@ -62,9 +62,9 @@ inline DataSpace::DataSpace(const std::vector& dims, const std::vector DataSpace::getDimensions() const { } inline size_t DataSpace::getElementCount() const { - const std::vector& dims = getDimensions(); - return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies()); + hssize_t nelements = H5Sget_simple_extent_npoints(_hid); + if (nelements < 0) { + HDF5ErrMapper::ToException( + "Unable to get number of elements in dataspace"); + } + + return static_cast(nelements); } inline std::vector DataSpace::getMaxDimensions() const { diff --git a/modules/drivers/highfive/include/highfive/bits/H5File_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5File_misc.hpp index a63338b82..b90792a71 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5File_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5File_misc.hpp @@ -127,4 +127,22 @@ inline void File::flush() { } } +inline size_t File::getFileSize() const { + hsize_t sizeValue = 0; + if (H5Fget_filesize(_hid, &sizeValue) < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to retrieve size of file " + getName())); + } + return static_cast(sizeValue); +} + +inline size_t File::getFreeSpace() const { + hssize_t unusedSize = H5Fget_freespace(_hid); + if (unusedSize < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to retrieve unused space of file " + getName())); + } + return static_cast(unusedSize); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/H5Inspector_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Inspector_misc.hpp new file mode 100644 index 000000000..05ed6bc3e --- /dev/null +++ b/modules/drivers/highfive/include/highfive/bits/H5Inspector_misc.hpp @@ -0,0 +1,858 @@ +/* + * Copyright (c) 2022 Blue Brain Project + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include "../H5Reference.hpp" + +#include "string_padding.hpp" + +#ifdef H5_USE_BOOST +#include +// starting Boost 1.64, serialization header must come before ublas +#include +#include +#endif +#ifdef H5_USE_EIGEN +#include +#endif + + +namespace HighFive { + +namespace details { + +inline bool checkDimensions(const std::vector& dims, size_t n_dim_requested) { + size_t n_dim_actual = dims.size(); + + // We should allow reading scalar from shapes like `(1, 1, 1)`. + if (n_dim_requested == 0) { + if (n_dim_actual == 0ul) { + return true; + } + + return size_t(std::count(dims.begin(), dims.end(), 1ul)) == n_dim_actual; + } + + // For non-scalar datasets, we can squeeze away singleton dimension, but + // we never add any. + if (n_dim_actual < n_dim_requested) { + return false; + } + + // Special case for 1-dimensional arrays, which can squeeze `1`s from either + // side simultaneously if needed. + if (n_dim_requested == 1ul) { + return n_dim_actual >= 1ul && + size_t(std::count(dims.begin(), dims.end(), 1ul)) >= n_dim_actual - 1ul; + } + + // All other cases strip front only. This avoid unstable behaviour when + // squeezing singleton dimensions. + size_t n_dim_excess = n_dim_actual - n_dim_requested; + + bool squeeze_back = true; + for (size_t i = 1; i <= n_dim_excess; ++i) { + if (dims[n_dim_actual - i] != 1) { + squeeze_back = false; + break; + } + } + + return squeeze_back; +} + + +inline std::vector squeezeDimensions(const std::vector& dims, + size_t n_dim_requested) { + auto format_error_message = [&]() -> std::string { + return "Can't interpret dims = " + format_vector(dims) + " as " + + std::to_string(n_dim_requested) + "-dimensional."; + }; + + if (n_dim_requested == 0) { + if (!checkDimensions(dims, n_dim_requested)) { + throw std::invalid_argument(format_error_message()); + } + + return {1ul}; + } + + auto n_dim = dims.size(); + if (n_dim < n_dim_requested) { + throw std::invalid_argument(format_error_message()); + } + + if (n_dim_requested == 1ul) { + size_t non_singleton_dim = size_t(-1); + for (size_t i = 0; i < n_dim; ++i) { + if (dims[i] != 1ul) { + if (non_singleton_dim == size_t(-1)) { + non_singleton_dim = i; + } else { + throw std::invalid_argument(format_error_message()); + } + } + } + + return {dims[std::min(non_singleton_dim, n_dim - 1)]}; + } + + size_t n_dim_excess = dims.size() - n_dim_requested; + for (size_t i = 1; i <= n_dim_excess; ++i) { + if (dims[n_dim - i] != 1) { + throw std::invalid_argument(format_error_message()); + } + } + + return std::vector(dims.begin(), + dims.end() - static_cast(n_dim_excess)); +} +} // namespace details + + +inline size_t compute_total_size(const std::vector& dims) { + return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies()); +} + +template +using unqualified_t = typename std::remove_const::type>::type; + +/***** +inspector { + using type = T + // base_type is the base type inside c++ (e.g. std::vector => int) + using base_type + // hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector => const char*) + using hdf5_type + + // Number of dimensions starting from here + static constexpr size_t recursive_ndim + // Is the inner type trivially copyable for optimisation + // If this value is true: data() is mandatory + // If this value is false: getSizeVal, getSize, serialize, unserialize are mandatory + static constexpr bool is_trivially_copyable + + // Reading: + // Allocate the value following dims (should be recursive) + static void prepare(type& val, const std::vector dims) + // Return the size of the vector pass to/from hdf5 from a vector of dims + static size_t getSize(const std::vector& dims) + // Return a pointer of the first value of val (for reading) + static hdf5_type* data(type& val) + // Take a serialized vector 'in', some dims and copy value to val (for reading) + static void unserialize(const hdf5_type* in, const std::vector&i, type& val) + + + // Writing: + // Return the size of the vector pass to/from hdf5 from a value + static size_t getSizeVal(const type& val) + // Return a point of the first value of val + static const hdf5_type* data(const type& val) + // Take a val and serialize it inside 'out' + static void serialize(const type& val, hdf5_type* out) + // Return an array of dimensions of the space needed for writing val + static std::vector getDimensions(const type& val) +} +*****/ + + +namespace details { +template +struct type_helper { + using type = unqualified_t; + using base_type = unqualified_t; + using hdf5_type = base_type; + + static constexpr size_t ndim = 0; + static constexpr size_t recursive_ndim = ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value; + + static std::vector getDimensions(const type& /* val */) { + return {}; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& /* val */, const std::vector& /* dims */) {} + + static hdf5_type* data(type& val) { + static_assert(is_trivially_copyable, "The type is not trivially copyable"); + return &val; + } + + static const hdf5_type* data(const type& val) { + static_assert(is_trivially_copyable, "The type is not trivially copyable"); + return &val; + } + + static void serialize(const type& val, hdf5_type* m) { + static_assert(is_trivially_copyable, "The type is not trivially copyable"); + *m = val; + } + + static void unserialize(const hdf5_type* vec, + const std::vector& /* dims */, + type& val) { + static_assert(is_trivially_copyable, "The type is not trivially copyable"); + val = vec[0]; + } +}; + +template +struct inspector: type_helper {}; + +enum class Boolean : int8_t { + HighFiveFalse = 0, + HighFiveTrue = 1, +}; + +template <> +struct inspector: type_helper { + using base_type = Boolean; + using hdf5_type = int8_t; + + static constexpr bool is_trivially_copyable = false; + + static hdf5_type* data(type& /* val */) { + throw DataSpaceException("A boolean cannot be read directly."); + } + + static const hdf5_type* data(const type& /* val */) { + throw DataSpaceException("A boolean cannot be written directly."); + } + + static void unserialize(const hdf5_type* vec, + const std::vector& /* dims */, + type& val) { + val = vec[0] != 0 ? true : false; + } + + static void serialize(const type& val, hdf5_type* m) { + *m = val ? 1 : 0; + } +}; + +template <> +struct inspector: type_helper { + using hdf5_type = const char*; + + static hdf5_type* data(type& /* val */) { + throw DataSpaceException("A std::string cannot be read directly."); + } + + static const hdf5_type* data(const type& /* val */) { + throw DataSpaceException("A std::string cannot be written directly."); + } + + template + static void serialize(const type& val, It m) { + (*m).assign(val.data(), val.size(), StringPadding::NullTerminated); + } + + template + static void unserialize(const It& vec, const std::vector& /* dims */, type& val) { + const auto& view = *vec; + val.assign(view.data(), view.length()); + } +}; + +template <> +struct inspector: type_helper { + using hdf5_type = hobj_ref_t; + + static constexpr bool is_trivially_copyable = false; + + static hdf5_type* data(type& /* val */) { + throw DataSpaceException("A Reference cannot be read directly."); + } + + static const hdf5_type* data(const type& /* val */) { + throw DataSpaceException("A Reference cannot be written directly."); + } + + static void serialize(const type& val, hdf5_type* m) { + hobj_ref_t ref; + val.create_ref(&ref); + *m = ref; + } + + static void unserialize(const hdf5_type* vec, + const std::vector& /* dims */, + type& val) { + val = type{vec[0]}; + } +}; + +template +struct inspector> { + using type = FixedLenStringArray; + using value_type = char*; + using base_type = FixedLenStringArray; + using hdf5_type = char; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim; + static constexpr bool is_trivially_copyable = false; + + static std::vector getDimensions(const type& val) { + return std::vector{val.size()}; + } + + static size_t getSizeVal(const type& val) { + return N * compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return N * compute_total_size(dims); + } + + static void prepare(type& /* val */, const std::vector& dims) { + if (dims[0] > N) { + std::ostringstream os; + os << "Size of FixedlenStringArray (" << N << ") is too small for dims (" << dims[0] + << ")."; + throw DataSpaceException(os.str()); + } + } + + static hdf5_type* data(type& val) { + return val.data(); + } + + static const hdf5_type* data(const type& val) { + return val.data(); + } + + static void serialize(const type& val, hdf5_type* m) { + for (size_t i = 0; i < val.size(); ++i) { + std::memcpy(m + i * N, val[i], N); + } + } + + static void unserialize(const hdf5_type* vec, const std::vector& dims, type& val) { + for (size_t i = 0; i < dims[0]; ++i) { + std::array s; + std::memcpy(s.data(), vec + (i * N), N); + val.push_back(s); + } + } +}; + +template +struct inspector> { + using type = std::vector; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + static std::vector getDimensions(const type& val) { + std::vector sizes(recursive_ndim, 1ul); + sizes[0] = val.size(); + if (!val.empty()) { + auto s = inspector::getDimensions(val[0]); + assert(s.size() + ndim == sizes.size()); + for (size_t i = 0; i < s.size(); ++i) { + sizes[i + ndim] = s[i]; + } + } + return sizes; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& val, const std::vector& dims) { + val.resize(dims[0]); + std::vector next_dims(dims.begin() + 1, dims.end()); + for (auto&& e: val) { + inspector::prepare(e, next_dims); + } + } + + static hdf5_type* data(type& val) { + return inspector::data(val[0]); + } + + static const hdf5_type* data(const type& val) { + return inspector::data(val[0]); + } + + template + static void serialize(const type& val, It m) { + size_t subsize = inspector::getSizeVal(val[0]); + for (auto&& e: val) { + inspector::serialize(e, m); + m += subsize; + } + } + + template + static void unserialize(const It& vec_align, const std::vector& dims, type& val) { + std::vector next_dims(dims.begin() + 1, dims.end()); + size_t next_size = compute_total_size(next_dims); + for (size_t i = 0; i < dims[0]; ++i) { + inspector::unserialize(vec_align + i * next_size, next_dims, val[i]); + } + } +}; + +template <> +struct inspector> { + using type = std::vector; + using value_type = bool; + using base_type = Boolean; + using hdf5_type = uint8_t; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim; + static constexpr bool is_trivially_copyable = false; + + static std::vector getDimensions(const type& val) { + std::vector sizes{val.size()}; + return sizes; + } + + static size_t getSizeVal(const type& val) { + return val.size(); + } + + static size_t getSize(const std::vector& dims) { + if (dims.size() > 1) { + throw DataSpaceException("std::vector is only 1 dimension."); + } + return dims[0]; + } + + static void prepare(type& val, const std::vector& dims) { + if (dims.size() > 1) { + throw DataSpaceException("std::vector is only 1 dimension."); + } + val.resize(dims[0]); + } + + static hdf5_type* data(type& /* val */) { + throw DataSpaceException("A std::vector cannot be read directly."); + } + + static const hdf5_type* data(const type& /* val */) { + throw DataSpaceException("A std::vector cannot be written directly."); + } + + static void serialize(const type& val, hdf5_type* m) { + for (size_t i = 0; i < val.size(); ++i) { + m[i] = val[i] ? 1 : 0; + } + } + + static void unserialize(const hdf5_type* vec_align, + const std::vector& dims, + type& val) { + for (size_t i = 0; i < dims[0]; ++i) { + val[i] = vec_align[i] != 0 ? true : false; + } + } +}; + +template +struct inspector> { + using type = std::array; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + sizeof(type) == N * sizeof(T) && + inspector::is_trivially_copyable; + + static std::vector getDimensions(const type& val) { + std::vector sizes{N}; + if (!val.empty()) { + auto s = inspector::getDimensions(val[0]); + sizes.insert(sizes.end(), s.begin(), s.end()); + } + return sizes; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& /* val */, const std::vector& dims) { + if (dims[0] > N) { + std::ostringstream os; + os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ")."; + throw DataSpaceException(os.str()); + } + } + + static hdf5_type* data(type& val) { + return inspector::data(val[0]); + } + + static const hdf5_type* data(const type& val) { + return inspector::data(val[0]); + } + + template + static void serialize(const type& val, It m) { + size_t subsize = inspector::getSizeVal(val[0]); + for (auto& e: val) { + inspector::serialize(e, m); + m += subsize; + } + } + + template + static void unserialize(const It& vec_align, const std::vector& dims, type& val) { + if (dims[0] != N) { + std::ostringstream os; + os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with " + << N << " elements."; + throw DataSpaceException(os.str()); + } + std::vector next_dims(dims.begin() + 1, dims.end()); + size_t next_size = compute_total_size(next_dims); + for (size_t i = 0; i < dims[0]; ++i) { + inspector::unserialize(vec_align + i * next_size, next_dims, val[i]); + } + } +}; + +// Cannot be use for reading +template +struct inspector { + using type = T*; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + static size_t getSizeVal(const type& /* val */) { + throw DataSpaceException("Not possible to have size of a T*"); + } + + static std::vector getDimensions(const type& /* val */) { + throw DataSpaceException("Not possible to have size of a T*"); + } + + static const hdf5_type* data(const type& val) { + return reinterpret_cast(val); + } + + /* it works because there is only T[][][] currently + we will fix it one day */ + static void serialize(const type& /* val */, hdf5_type* /* m */) { + throw DataSpaceException("Not possible to serialize a T*"); + } +}; + +// Cannot be use for reading +template +struct inspector { + using type = T[N]; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 1; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static std::vector getDimensions(const type& val) { + std::vector sizes{N}; + if (N > 0) { + auto s = inspector::getDimensions(val[0]); + sizes.insert(sizes.end(), s.begin(), s.end()); + } + return sizes; + } + + static const hdf5_type* data(const type& val) { + return inspector::data(val[0]); + } + + /* it works because there is only T[][][] currently + we will fix it one day */ + static void serialize(const type& val, hdf5_type* m) { + size_t subsize = inspector::getSizeVal(val[0]); + for (size_t i = 0; i < N; ++i) { + inspector::serialize(val[i], m + i * subsize); + } + } +}; + +#ifdef H5_USE_EIGEN +template +struct inspector> { + using type = Eigen::Matrix; + using value_type = T; + using base_type = typename inspector::base_type; + using hdf5_type = base_type; + + static constexpr size_t ndim = 2; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + + static void assert_not_buggy(Eigen::Index nrows, Eigen::Index ncols) { + if (nrows > 1 && ncols > 1) { + throw std::runtime_error( + "HighFive has been broken for Eigen::Matrix. Please check " + "https://github.com/BlueBrain/HighFive/issues/532."); + } + } + + static std::vector getDimensions(const type& val) { + assert_not_buggy(val.rows(), val.cols()); + + std::vector sizes{static_cast(val.rows()), static_cast(val.cols())}; + auto s = inspector::getDimensions(val.data()[0]); + sizes.insert(sizes.end(), s.begin(), s.end()); + return sizes; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& val, const std::vector& dims) { + if (dims[0] != static_cast(val.rows()) || + dims[1] != static_cast(val.cols())) { + val.resize(static_cast(dims[0]), + static_cast(dims[1])); + } + + assert_not_buggy(val.rows(), val.cols()); + } + + static hdf5_type* data(type& val) { + assert_not_buggy(val.rows(), val.cols()); + return inspector::data(*val.data()); + } + + static const hdf5_type* data(const type& val) { + assert_not_buggy(val.rows(), val.cols()); + return inspector::data(*val.data()); + } + + static void serialize(const type& val, hdf5_type* m) { + assert_not_buggy(val.rows(), val.cols()); + std::memcpy(m, val.data(), static_cast(val.size()) * sizeof(hdf5_type)); + } + + static void unserialize(const hdf5_type* vec_align, + const std::vector& dims, + type& val) { + assert_not_buggy(val.rows(), val.cols()); + if (dims.size() < 2) { + std::ostringstream os; + os << "Impossible to pair DataSet with " << dims.size() + << " dimensions into an eigen-matrix."; + throw DataSpaceException(os.str()); + } + std::memcpy(val.data(), vec_align, compute_total_size(dims) * sizeof(hdf5_type)); + } +}; +#endif + +#ifdef H5_USE_BOOST +template +struct inspector> { + using type = boost::multi_array; + using value_type = T; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = Dims; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + static std::vector getDimensions(const type& val) { + std::vector sizes; + for (size_t i = 0; i < ndim; ++i) { + sizes.push_back(val.shape()[i]); + } + auto s = inspector::getDimensions(val.data()[0]); + sizes.insert(sizes.end(), s.begin(), s.end()); + return sizes; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& val, const std::vector& dims) { + if (dims.size() < ndim) { + std::ostringstream os; + os << "Only '" << dims.size() << "' given but boost::multi_array is of size '" << ndim + << "'."; + throw DataSpaceException(os.str()); + } + boost::array ext; + std::copy(dims.begin(), dims.begin() + ndim, ext.begin()); + val.resize(ext); + std::vector next_dims(dims.begin() + Dims, dims.end()); + std::size_t size = std::accumulate(dims.begin(), + dims.begin() + Dims, + std::size_t{1}, + std::multiplies()); + for (size_t i = 0; i < size; ++i) { + inspector::prepare(*(val.origin() + i), next_dims); + } + } + + static hdf5_type* data(type& val) { + return inspector::data(*val.data()); + } + + static const hdf5_type* data(const type& val) { + return inspector::data(*val.data()); + } + + template + static void serialize(const type& val, It m) { + size_t size = val.num_elements(); + size_t subsize = inspector::getSizeVal(*val.origin()); + for (size_t i = 0; i < size; ++i) { + inspector::serialize(*(val.origin() + i), m + i * subsize); + } + } + + template + static void unserialize(It vec_align, const std::vector& dims, type& val) { + std::vector next_dims(dims.begin() + ndim, dims.end()); + size_t subsize = compute_total_size(next_dims); + for (size_t i = 0; i < val.num_elements(); ++i) { + inspector::unserialize(vec_align + i * subsize, + next_dims, + *(val.origin() + i)); + } + } +}; + +template +struct inspector> { + using type = boost::numeric::ublas::matrix; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 2; + static constexpr size_t recursive_ndim = ndim + inspector::recursive_ndim; + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_copyable; + + static std::vector getDimensions(const type& val) { + std::vector sizes{val.size1(), val.size2()}; + auto s = inspector::getDimensions(val(0, 0)); + sizes.insert(sizes.end(), s.begin(), s.end()); + return sizes; + } + + static size_t getSizeVal(const type& val) { + return compute_total_size(getDimensions(val)); + } + + static size_t getSize(const std::vector& dims) { + return compute_total_size(dims); + } + + static void prepare(type& val, const std::vector& dims) { + if (dims.size() < ndim) { + std::ostringstream os; + os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim + << " boost::numeric::ublas::matrix"; + throw DataSpaceException(os.str()); + } + val.resize(dims[0], dims[1], false); + } + + static hdf5_type* data(type& val) { + return inspector::data(val(0, 0)); + } + + static const hdf5_type* data(const type& val) { + return inspector::data(val(0, 0)); + } + + static void serialize(const type& val, hdf5_type* m) { + size_t size = val.size1() * val.size2(); + size_t subsize = inspector::getSizeVal(val(0, 0)); + for (size_t i = 0; i < size; ++i) { + inspector::serialize(*(&val(0, 0) + i), m + i * subsize); + } + } + + static void unserialize(const hdf5_type* vec_align, + const std::vector& dims, + type& val) { + std::vector next_dims(dims.begin() + ndim, dims.end()); + size_t subsize = compute_total_size(next_dims); + size_t size = val.size1() * val.size2(); + for (size_t i = 0; i < size; ++i) { + inspector::unserialize(vec_align + i * subsize, + next_dims, + *(&val(0, 0) + i)); + } + } +}; +#endif + +} // namespace details +} // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/H5Node_traits.hpp b/modules/drivers/highfive/include/highfive/bits/H5Node_traits.hpp index bdd70332e..d53d3f048 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Node_traits.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Node_traits.hpp @@ -129,6 +129,14 @@ class NodeTraits { /// \return the group object Group getGroup(const std::string& group_name) const; + /// + /// \brief open a commited datatype with the name type_name + /// \param type_name + /// \return the datatype object + DataType getDataType( + const std::string& type_name, + const DataTypeAccessProps& accessProps = DataTypeAccessProps::Default()) const; + /// /// \brief return the number of leaf objects of the node / group /// \return number of leaf objects @@ -208,6 +216,20 @@ class NodeTraits { const LinkAccessProps& linkAccessProps = LinkAccessProps(), const bool parents = true); + /// + /// \brief Creates hardlinks + /// \param link_name The name of the link + /// \param target_obj The target object + /// \param linkCreateProps A Link_Create property list. Notice "parents=true" overrides + /// \param linkAccessProps The Link_Access property list + /// \param parents Whether parent groups should be created: Default: true + template + void createHardLink(const std::string& link_name, + const T& target_obj, + LinkCreateProps linkCreateProps = LinkCreateProps(), + const LinkAccessProps& linkAccessProps = LinkAccessProps(), + const bool parents = true); + private: using derivate_type = Derivate; diff --git a/modules/drivers/highfive/include/highfive/bits/H5Node_traits_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Node_traits_misc.hpp index 0af128175..2f75ff311 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Node_traits_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Node_traits_misc.hpp @@ -174,6 +174,19 @@ inline Group NodeTraits::getGroup(const std::string& group_name) const return detail::make_group(hid); } +template +inline DataType NodeTraits::getDataType(const std::string& type_name, + const DataTypeAccessProps& accessProps) const { + const auto hid = H5Topen2(static_cast(this)->getId(), + type_name.c_str(), + accessProps.getId()); + if (hid < 0) { + HDF5ErrMapper::ToException( + std::string("Unable to open the datatype \"") + type_name + "\":"); + } + return DataType(hid); +} + template inline size_t NodeTraits::getNumberObjects() const { hsize_t res; @@ -358,6 +371,29 @@ inline void NodeTraits::createExternalLink(const std::string& link_nam } } +template +template +inline void NodeTraits::createHardLink(const std::string& link_name, + const T& target_obj, + LinkCreateProps linkCreateProps, + const LinkAccessProps& linkAccessProps, + const bool parents) { + static_assert(!std::is_same::value, + "hdf5 doesn't support hard links to Attributes"); + if (parents) { + linkCreateProps.add(CreateIntermediateGroup{}); + } + auto status = H5Lcreate_hard(target_obj.getId(), + ".", + static_cast(this)->getId(), + link_name.c_str(), + linkCreateProps.getId(), + linkAccessProps.getId()); + if (status < 0) { + HDF5ErrMapper::ToException(std::string("Unable to create hard link: ")); + } +} + template inline Object NodeTraits::_open(const std::string& node_name, diff --git a/modules/drivers/highfive/include/highfive/bits/H5Path_traits_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Path_traits_misc.hpp index 73704f03a..444e9294b 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Path_traits_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Path_traits_misc.hpp @@ -34,7 +34,7 @@ inline PathTraits::PathTraits() { template inline std::string PathTraits::getPath() const { return details::get_name([this](char* buffer, size_t length) { - return H5Iget_name(static_cast(this)->getId(), buffer, length); + return H5Iget_name(static_cast(*this).getId(), buffer, length); }); } diff --git a/modules/drivers/highfive/include/highfive/bits/H5PropertyList_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5PropertyList_misc.hpp index 6a4ef9efd..cef301e53 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5PropertyList_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5PropertyList_misc.hpp @@ -70,7 +70,7 @@ inline void PropertyList::_initializeIfNeeded() { } template -template +template inline void PropertyList::add(const P& property) { _initializeIfNeeded(); property.apply(_hid); @@ -543,4 +543,32 @@ inline void LinkCreationOrder::fromPropertyList(hid_t hid) { "Error getting property for link creation order"); } } + +inline AttributePhaseChange::AttributePhaseChange(unsigned max_compact, unsigned min_dense) + : _max_compact(max_compact) + , _min_dense(min_dense) {} + +inline AttributePhaseChange::AttributePhaseChange(const GroupCreateProps& gcpl) { + if (H5Pget_attr_phase_change(gcpl.getId(), &_max_compact, &_min_dense) < 0) { + HDF5ErrMapper::ToException( + "Error getting property for attribute phase change"); + } +} + +inline unsigned AttributePhaseChange::max_compact() const { + return _max_compact; +} + +inline unsigned AttributePhaseChange::min_dense() const { + return _min_dense; +} + +inline void AttributePhaseChange::apply(hid_t hid) const { + if (H5Pset_attr_phase_change(hid, _max_compact, _min_dense) < 0) { + HDF5ErrMapper::ToException( + "Error getting property for attribute phase change"); + } +} + + } // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/H5ReadWrite_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5ReadWrite_misc.hpp index 491e61389..c8e736174 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5ReadWrite_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5ReadWrite_misc.hpp @@ -19,9 +19,13 @@ template using unqualified_t = typename std::remove_const::type>::type; // Find the type of an eventual char array, otherwise void -template +template struct type_char_array { - using type = void; + using type = typename std::conditional< + std::is_same::base_type, std::string>::value, + std::string, + void>::type; + static constexpr bool is_char_array = false; }; template @@ -29,6 +33,7 @@ struct type_char_array { using type = typename std::conditional, char>::value, char*, typename type_char_array::type>::type; + static constexpr bool is_char_array = true; }; template @@ -36,6 +41,7 @@ struct type_char_array { using type = typename std::conditional, char>::value, char[N], typename type_char_array::type>::type; + static constexpr bool is_char_array = true; }; template @@ -43,7 +49,7 @@ struct BufferInfo { using type_no_const = typename std::remove_const::type; using elem_type = typename details::inspector::base_type; using char_array_t = typename details::type_char_array::type; - static constexpr bool is_char_array = !std::is_same::value; + static constexpr bool is_char_array = details::type_char_array::is_char_array; enum Operation { read, write }; const Operation op; @@ -63,29 +69,44 @@ struct string_type_checker { static DataType getDataType(const DataType&, const DataType&); }; +inline void enforce_ascii_hack(const DataType& dst, const DataType& src) { + // Note: constness only refers to constness of the DataType object, which + // is just an ID, we can/will change properties of `dst`. + + // TEMP. CHANGE: Ensure that the character set is properly configured to prevent + // converter issues on HDF5 <=v1.12.0 when loading ASCII strings first. + // See https://github.com/HDFGroup/hdf5/issues/544 for further information. + if (H5Tget_cset(src.getId()) == H5T_CSET_ASCII) { + H5Tset_cset(dst.getId(), H5T_CSET_ASCII); + } +} + template <> struct string_type_checker { inline static DataType getDataType(const DataType& element_type, const DataType& dtype) { - // TEMP. CHANGE: Ensure that the character set is properly configured to prevent - // converter issues on HDF5 <=v1.12.0 when loading ASCII strings first. - // See https://github.com/HDFGroup/hdf5/issues/544 for further information. - if (H5Tget_class(element_type.getId()) == H5T_STRING && - H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(element_type.getId(), H5T_CSET_ASCII); + if (H5Tget_class(element_type.getId()) == H5T_STRING) { + enforce_ascii_hack(element_type, dtype); } return element_type; } }; +template <> +struct string_type_checker { + inline static DataType getDataType(const DataType&, const DataType& file_datatype) { + // The StringBuffer ensures that the data is transformed such that it + // matches the datatype of the dataset, i.e. `file_datatype` and + // `mem_datatype` are the same. + return file_datatype; + } +}; + template struct string_type_checker { inline static DataType getDataType(const DataType& element_type, const DataType& dtype) { DataType return_type = (dtype.isFixedLenStr()) ? AtomicType() : element_type; - // TEMP. CHANGE: See string_type_checker definition - if (H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(return_type.getId(), H5T_CSET_ASCII); - } + enforce_ascii_hack(return_type, dtype); return return_type; } }; @@ -93,13 +114,11 @@ struct string_type_checker { template <> struct string_type_checker { inline static DataType getDataType(const DataType&, const DataType& dtype) { - if (dtype.isFixedLenStr()) + if (dtype.isFixedLenStr()) { throw DataSetException("Can't output variable-length to fixed-length strings"); - // TEMP. CHANGE: See string_type_checker definition - DataType return_type = AtomicType(); - if (H5Tget_cset(dtype.getId()) == H5T_CSET_ASCII) { - H5Tset_cset(return_type.getId(), H5T_CSET_ASCII); } + DataType return_type = AtomicType(); + enforce_ascii_hack(return_type, dtype); return return_type; } }; @@ -114,11 +133,6 @@ BufferInfo::BufferInfo(const DataType& dtype, F getName, Operation _op) ((is_fixed_len_string && is_char_array) ? 1 : 0)) , data_type( string_type_checker::getDataType(create_datatype(), dtype)) { - if (is_fixed_len_string && std::is_same::value) { - throw DataSetException( - "Can't output std::string as fixed-length. " - "Use raw arrays or FixedLenStringArray"); - } // We warn. In case they are really not convertible an exception will rise on read/write if (dtype.getClass() != data_type.getClass()) { HIGHFIVE_LOG_WARN(getName() + "\": data and hdf5 dataset have different types: " + diff --git a/modules/drivers/highfive/include/highfive/bits/H5Slice_traits.hpp b/modules/drivers/highfive/include/highfive/bits/H5Slice_traits.hpp index 719b4e503..52c52713f 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Slice_traits.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Slice_traits.hpp @@ -258,6 +258,15 @@ class SliceTraits { /// Therefore, the only memspaces supported for general hyperslabs are one-dimensional arrays. Selection select(const HyperSlab& hyperslab) const; + /// + /// \brief Select an \p hyperslab in the current Slice/Dataset. + /// + /// If the selection can be read into a simple, multi-dimensional dataspace, + /// then this overload enable specifying the shape of the memory dataspace + /// with `memspace`. Note, that simple implies no offsets, strides or + /// number of blocks, just the size of the block in each dimension. + Selection select(const HyperSlab& hyperslab, const DataSpace& memspace) const; + /// /// \brief Select a region in the current Slice/Dataset of \p count points at /// \p offset separated by \p stride. If strides are not provided they will @@ -308,9 +317,21 @@ class SliceTraits { /// \param xfer_props: Data Transfer properties template void read(T* array, - const DataType& dtype = DataType(), + const DataType& dtype, const DataTransferProps& xfer_props = DataTransferProps()) const; + /// + /// Read the entire dataset into a raw buffer + /// + /// Same as `read(T*, const DataType&, const DataTransferProps&)`. However, + /// this overload deduces the HDF5 datatype of the element of `array` from + /// `T`. Note, that the file datatype is already fixed. + /// + /// \param array: A buffer containing enough space for the data + /// \param xfer_props: Data Transfer properties + template + void read(T* array, const DataTransferProps& xfer_props = DataTransferProps()) const; + /// /// Write the integrality N-dimension buffer to this dataset /// An exception is raised is if the numbers of dimension of the buffer and @@ -322,22 +343,33 @@ class SliceTraits { void write(const T& buffer, const DataTransferProps& xfer_props = DataTransferProps()); /// - /// Write from a raw buffer into this dataset + /// Write from a raw pointer into this dataset. /// /// No dimensionality checks will be performed, it is the user's /// responsibility to ensure that the buffer holds the right amount of /// elements. For n-dimensional matrices the buffer layout follows H5 /// default conventions. + /// + /// Note, this is the shallowest wrapper around `H5Dwrite` and should + /// be used if full control is needed. Generally prefer `write`. + /// /// \param buffer: A buffer containing the data to be written - /// \param dtype: The type of the data, in case it cannot be automatically guessed + /// \param dtype: The datatype of `buffer`, i.e. the memory data type. /// \param xfer_props: The HDF5 data transfer properties, e.g. collective MPI-IO. template void write_raw(const T* buffer, - const DataType& dtype = DataType(), + const DataType& mem_datatype, const DataTransferProps& xfer_props = DataTransferProps()); - protected: - inline Selection select_impl(const HyperSlab& hyperslab, const DataSpace& memspace) const; + /// + /// Write from a raw pointer into this dataset. + /// + /// Same as `write_raw(const T*, const DataTransferProps&)`. However, this + /// overload attempts to guess the data type of `buffer`, i.e. the memory + /// datatype. Note that the file datatype is already fixed. + /// + template + void write_raw(const T* buffer, const DataTransferProps& xfer_props = DataTransferProps()); }; } // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/H5Slice_traits_misc.hpp b/modules/drivers/highfive/include/highfive/bits/H5Slice_traits_misc.hpp index faae237d8..7b07c9abf 100644 --- a/modules/drivers/highfive/include/highfive/bits/H5Slice_traits_misc.hpp +++ b/modules/drivers/highfive/include/highfive/bits/H5Slice_traits_misc.hpp @@ -64,8 +64,8 @@ inline ElementSet::ElementSet(const std::vector>& eleme } template -inline Selection SliceTraits::select_impl(const HyperSlab& hyperslab, - const DataSpace& memspace) const { +inline Selection SliceTraits::select(const HyperSlab& hyperslab, + const DataSpace& memspace) const { // Note: The current limitation are that memspace must describe a // packed memspace. // @@ -98,7 +98,7 @@ inline Selection SliceTraits::select(const std::vector& offset const std::vector& block) const { auto slab = HyperSlab(RegularHyperSlab(offset, count, stride, block)); auto memspace = DataSpace(count); - return select_impl(slab, memspace); + return select(slab, memspace); } template @@ -121,7 +121,7 @@ inline Selection SliceTraits::select(const std::vector& column std::vector memdims = dims; memdims.back() = columns.size(); - return select_impl(slab, DataSpace(memdims)); + return select(slab, DataSpace(memdims)); } template @@ -172,8 +172,10 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ const auto& slice = static_cast(*this); const DataSpace& mem_space = slice.getMemSpace(); + auto file_datatype = slice.getDataType(); + const details::BufferInfo buffer_info( - slice.getDataType(), + file_datatype, [&slice]() -> std::string { return details::get_dataset(slice).getPath(); }, details::BufferInfo::Operation::read); @@ -193,19 +195,20 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ return; } - auto r = details::data_converter::get_reader(dims, array); - read(r.get_pointer(), buffer_info.data_type, xfer_props); + auto r = details::data_converter::get_reader(dims, array, file_datatype); + read(r.getPointer(), buffer_info.data_type, xfer_props); // re-arrange results - r.unserialize(); - auto t = create_datatype::base_type>(); + r.unserialize(array); + + auto t = buffer_info.data_type; auto c = t.getClass(); if (c == DataTypeClass::VarLen || t.isVariableStr()) { #if H5_VERSION_GE(1, 12, 0) // This one have been created in 1.12.0 - (void) H5Treclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.get_pointer()); + (void) H5Treclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer()); #else // This one is deprecated since 1.12.0 - (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.get_pointer()); + (void) H5Dvlen_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer()); #endif } } @@ -214,16 +217,12 @@ inline void SliceTraits::read(T& array, const DataTransferProps& xfer_ template template inline void SliceTraits::read(T* array, - const DataType& dtype, + const DataType& mem_datatype, const DataTransferProps& xfer_props) const { static_assert(!std::is_const::value, "read() requires a non-const structure to read data into"); - const auto& slice = static_cast(*this); - using element_type = typename details::inspector::base_type; - // Auto-detect mem datatype if not provided - const DataType& mem_datatype = dtype.empty() ? create_and_check_datatype() - : dtype; + const auto& slice = static_cast(*this); if (H5Dread(details::get_dataset(slice).getId(), mem_datatype.getId(), @@ -235,6 +234,15 @@ inline void SliceTraits::read(T* array, } } +template +template +inline void SliceTraits::read(T* array, const DataTransferProps& xfer_props) const { + using element_type = typename details::inspector::base_type; + const DataType& mem_datatype = create_and_check_datatype(); + + read(array, mem_datatype, xfer_props); +} + template template @@ -246,8 +254,10 @@ inline void SliceTraits::write(const T& buffer, const DataTransferProp return; } + auto file_datatype = slice.getDataType(); + const details::BufferInfo buffer_info( - slice.getDataType(), + file_datatype, [&slice]() -> std::string { return details::get_dataset(slice).getPath(); }, details::BufferInfo::Operation::write); @@ -258,19 +268,17 @@ inline void SliceTraits::write(const T& buffer, const DataTransferProp << " into dataset with n = " << buffer_info.n_dimensions << " dimensions."; throw DataSpaceException(ss.str()); } - auto w = details::data_converter::serialize(buffer); - write_raw(w.get_pointer(), buffer_info.data_type, xfer_props); + auto w = details::data_converter::serialize(buffer, file_datatype); + write_raw(w.getPointer(), buffer_info.data_type, xfer_props); } template template inline void SliceTraits::write_raw(const T* buffer, - const DataType& dtype, + const DataType& mem_datatype, const DataTransferProps& xfer_props) { - using element_type = typename details::inspector::base_type; const auto& slice = static_cast(*this); - const auto& mem_datatype = dtype.empty() ? create_and_check_datatype() : dtype; if (H5Dwrite(details::get_dataset(slice).getId(), mem_datatype.getId(), @@ -282,5 +290,14 @@ inline void SliceTraits::write_raw(const T* buffer, } } +template +template +inline void SliceTraits::write_raw(const T* buffer, const DataTransferProps& xfer_props) { + using element_type = typename details::inspector::base_type; + const auto& mem_datatype = create_and_check_datatype(); + + write_raw(buffer, mem_datatype, xfer_props); +} + } // namespace HighFive diff --git a/modules/drivers/highfive/include/highfive/bits/string_padding.hpp b/modules/drivers/highfive/include/highfive/bits/string_padding.hpp new file mode 100644 index 000000000..e6e6908dd --- /dev/null +++ b/modules/drivers/highfive/include/highfive/bits/string_padding.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace HighFive { + +enum class StringPadding : std::underlying_type::type { + NullTerminated = H5T_STR_NULLTERM, + NullPadded = H5T_STR_NULLPAD, + SpacePadded = H5T_STR_SPACEPAD +}; + + +} diff --git a/modules/drivers/highfive/include/highfive/highfive.hpp b/modules/drivers/highfive/include/highfive/highfive.hpp new file mode 100644 index 000000000..f5e20cae9 --- /dev/null +++ b/modules/drivers/highfive/include/highfive/highfive.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/modules/drivers/highfive/include/import/highfive.h b/modules/drivers/highfive/include/import/highfive.h index 5780ca588..475015d11 100644 --- a/modules/drivers/highfive/include/import/highfive.h +++ b/modules/drivers/highfive/include/import/highfive.h @@ -30,6 +30,7 @@ #endif #include "highfive/H5Easy.hpp" +#incldue "highfive/highfive.hpp" #if _MSC_VER #pragma comment(lib, "shlwapi") // StrStrI() diff --git a/modules/drivers/highfive/unittests/tests_high_five.hpp b/modules/drivers/highfive/unittests/tests_high_five.hpp index 79866b463..0ebd58c44 100644 --- a/modules/drivers/highfive/unittests/tests_high_five.hpp +++ b/modules/drivers/highfive/unittests/tests_high_five.hpp @@ -12,6 +12,17 @@ #include #include #include +#include +#include +#include + +// We don't need windows specific functionality. However, to better detect defects caused by macros, +// we include this header. +// The list of identifiers is taken from `Boost::Predef`. +#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || \ + defined(__WINDOWS__) +#include +#endif using ldcomplex = std::complex; using dcomplex = std::complex; @@ -35,8 +46,8 @@ using base_test_types = std::tuple using float16_t = half_float::half; -using numerical_test_types = decltype( - std::tuple_cat(std::declval(), std::tuple())); +using numerical_test_types = + decltype(std::tuple_cat(std::declval(), std::tuple())); #else using numerical_test_types = base_test_types; #endif @@ -154,16 +165,22 @@ struct ContentGenerate { template inline std::string typeNameHelper() { std::string name = typeid(T).name(); -#if defined(WIN32) - // Replace illegal windows file path characters std::replace(std::begin(name), std::end(name), ' ', '_'); std::replace(std::begin(name), std::end(name), '<', '_'); std::replace(std::begin(name), std::end(name), '>', '_'); std::replace(std::begin(name), std::end(name), ':', '_'); -#endif - return name; + + if (name.size() > 64) { + std::stringstream hash; + hash << std::hex << std::hash{}(name); + + return hash.str(); + } else { + return name; + } } + template inline HighFive::DataSet readWriteDataset(const DataT& ndvec, DataT& result, @@ -185,4 +202,4 @@ inline HighFive::DataSet readWriteDataset(const DataT& ndvec, dataset.read(result); return dataset; -} \ No newline at end of file +} diff --git a/modules/drivers/highfive/unittests/tests_high_five_base.cpp b/modules/drivers/highfive/unittests/tests_high_five_base.cpp index 87358d8e1..8cbce8096 100644 --- a/modules/drivers/highfive/unittests/tests_high_five_base.cpp +++ b/modules/drivers/highfive/unittests/tests_high_five_base.cpp @@ -62,14 +62,15 @@ inline bool Equals_(const std::vector& lhs, const std::vector& rhs) #define CHECK_NOTHROW(f) (f); TEST_SUCCESS #define REQUIRE(x) TEST_ASSERT_TRUE(x) #define CHECK_THAT(x, y) TEST_ASSERT(Equals_(x, y)) -#define INFO(...) {} +#define INFO(...) { } #define SECTION(name) +#include #include "tests_high_five.hpp" -TEST_CASE(Basic_HighFive_tests) { - using namespace HighFive; +using namespace HighFive; +TEST_CASE(Basic_HighFive_tests) { const std::string file_name("h5tutr_dset.h5"); const std::string dataset_name("dset"); @@ -108,8 +109,6 @@ TEST_CASE(Basic_HighFive_tests) { } TEST_CASE(Test_silent_HighFive) { - using namespace HighFive; - // Setting up a buffer for stderr so we can detect if the stack trace // was disabled fflush(stderr); @@ -131,8 +130,6 @@ TEST_CASE(Test_silent_HighFive) { } TEST_CASE(Test_open_modes_in_HighFive) { - using namespace HighFive; - const std::string file_name("openmodes.h5"); std::remove(file_name.c_str()); @@ -171,8 +168,6 @@ TEST_CASE(Test_open_modes_in_HighFive) { } TEST_CASE(Test_file_version_bounds) { - using namespace HighFive; - const std::string file_name("h5_version_bounds.h5"); std::remove(file_name.c_str()); @@ -196,9 +191,8 @@ TEST_CASE(Test_file_version_bounds) { } } +#if H5_VERSION_GE(1, 10, 1) TEST_CASE(Test_file_space_strategy) { - using namespace HighFive; - const std::string file_name("h5_file_space_strategy.h5"); auto strategies = std::vector{H5F_FSPACE_STRATEGY_FSM_AGGR, H5F_FSPACE_STRATEGY_AGGR, @@ -221,8 +215,6 @@ TEST_CASE(Test_file_space_strategy) { } TEST_CASE(Test_file_space_page_size) { - using namespace HighFive; - const std::string file_name("h5_file_space_page_size.h5"); hsize_t page_size = 1024; { @@ -241,8 +233,6 @@ TEST_CASE(Test_file_space_page_size) { #ifndef H5_HAVE_PARALLEL TEST_CASE(Test_page_buffer_size) { - using namespace HighFive; - const std::string file_name("h5_page_buffer_size.h5"); hsize_t page_size = 1024; { @@ -304,10 +294,9 @@ TEST_CASE(Test_page_buffer_size) { } } #endif +#endif TEST_CASE(Test_metadata_block_size_assignment) { - using namespace HighFive; - const std::string file_name("h5_meta_block_size.h5"); std::remove(file_name.c_str()); @@ -329,8 +318,6 @@ TEST_CASE(Test_metadata_block_size_assignment) { } TEST_CASE(Test_group_properties) { - using namespace HighFive; - const std::string file_name("h5_group_properties.h5"); FileAccessProps fapl; // When using hdf5 1.10.2 and later, the lower bound may be set to @@ -339,17 +326,15 @@ TEST_CASE(Test_group_properties) { File file(file_name, File::Truncate, fapl); GroupCreateProps props; - props.add(EstimatedLinkInfo(1000, 500)); + props.add(EstimatedLinkInfo(10, 60)); auto group = file.createGroup("g", props); auto sizes = group.getEstimatedLinkInfo(); - CHECK(sizes.first == 1000); - CHECK(sizes.second == 500); + CHECK(sizes.first == 10); + CHECK(sizes.second == 60); } TEST_CASE(Test_allocation_time) { - using namespace HighFive; - const std::string file_name("h5_dataset_alloc_time.h5"); File file(file_name, File::Truncate); @@ -367,15 +352,21 @@ TEST_CASE(Test_allocation_time) { CHECK(alloc_size == data.size() * sizeof(decltype(data)::value_type)); } +/* + * Test to ensure legacy support: DataSet used to have a default constructor. + * However, it is not useful to have a DataSet object that does not actually + * refer to a dataset in a file. Hence, the the default constructor was + * deprecated. + * This test is to ensure that the constructor is not accidentally removed and + * thereby break users' code. + */ TEST_CASE(Test_default_constructors) { - using namespace HighFive; - - const std::string file_name("h5_group_test.h5"); + const std::string file_name("h5_default_ctors.h5"); const std::string dataset_name("dset"); File file(file_name, File::Truncate); auto ds = file.createDataSet(dataset_name, std::vector{1, 2, 3, 4, 5}); - DataSet d2; // deprecated as it constructs unsafe objects + DataSet d2; // expect deprecation warning, as it constructs unsafe object // d2.getFile(); // runtime error CHECK(!d2.isValid()); d2 = ds; // copy @@ -383,8 +374,6 @@ TEST_CASE(Test_default_constructors) { } TEST_CASE(Test_groups_and_datasets) { - using namespace HighFive; - const std::string file_name("h5_group_test.h5"); const std::string dataset_name("dset"); const std::string chunked_dataset_name("chunked_dset"); @@ -480,9 +469,68 @@ TEST_CASE(Test_groups_and_datasets) { } } -TEST_CASE(Test_extensible_datasets) { - using namespace HighFive; +TEST_CASE(FileSpace) { + const std::string filename = "filespace.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + File file(filename, File::Truncate); + file.createDataSet(ds_path, data); + + CHECK(file.getFileSize() > 0); +} + +TEST_CASE(FreeSpace_default) { + const std::string filename = "freespace_default.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + { + File file(filename, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + } + + { + File file(filename, File::ReadWrite); + file.unlink(ds_path); + CHECK(file.getFreeSpace() > 0); + CHECK(file.getFreeSpace() < file.getFileSize()); + } +} + +#if H5_VERSION_GE(1, 10, 1) +TEST_CASE(FreeSpace_tracked) { + const std::string filename = "freespace_tracked.h5"; + const std::string ds_path = "dataset"; + const std::vector data{13, 24, 36}; + + { + FileCreateProps fcp; + fcp.add(FileSpaceStrategy(H5F_FSPACE_STRATEGY_FSM_AGGR, true, 0)); + File file(filename, File::Truncate, fcp); + auto dset = file.createDataSet(ds_path, data); + } + + { + File file(filename, File::ReadWrite); + file.unlink(ds_path); + +#if H5_VERSION_GE(1, 12, 0) + // This fails on 1.10.x but starts working in 1.12.0 + CHECK(file.getFreeSpace() > 0); +#endif + CHECK(file.getFreeSpace() < file.getFileSize()); + } + + { + File file(filename, File::ReadOnly); + CHECK(file.getFreeSpace() > 0); + CHECK(file.getFreeSpace() < file.getFileSize()); + } +} +#endif +TEST_CASE(Test_extensible_datasets) { const std::string file_name("create_extensible_dataset_example.h5"); const std::string dataset_name("dset"); constexpr long double t1[3][1] = {{2.0l}, {2.0l}, {4.0l}}; @@ -544,8 +592,6 @@ TEST_CASE(Test_extensible_datasets) { } TEST_CASE(Test_reference_count) { - using namespace HighFive; - const std::string file_name("h5_ref_count_test.h5"); const std::string dataset_name("dset"); const std::string group_name_1("/group1"); @@ -611,8 +657,6 @@ TEST_CASE(Test_reference_count) { } TEST_CASE(Test_simple_listings) { - using namespace HighFive; - const std::string file_name("h5_list_test.h5"); const std::string group_name_core("group_name"); const std::string group_nested_name("/group_nested"); @@ -675,8 +719,6 @@ TEST_CASE(Test_simple_listings) { } TEST_CASE(Simple_test_for_type_equality) { - using namespace HighFive; - AtomicType d_var; AtomicType size_var; AtomicType d_var_test; @@ -695,9 +737,46 @@ TEST_CASE(Simple_test_for_type_equality) { CHECK(int_var != uint_var); } -TEST_CASE(DataTypeEqualTakeBack) { - using namespace HighFive; +TEST_CASE(TestStringType) { + SECTION("enshrine-defaults") { + auto fixed_length = FixedLengthStringType(32, StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + REQUIRE(fixed_length.getCharacterSet() == CharacterSet::Ascii); + REQUIRE(variable_length.getCharacterSet() == CharacterSet::Ascii); + } + + SECTION("fixed-length") { + auto fixed_length = + FixedLengthStringType(32, StringPadding::SpacePadded, CharacterSet::Utf8); + auto string_type = fixed_length.asStringType(); + + REQUIRE(string_type.getId() == fixed_length.getId()); + REQUIRE(string_type.getCharacterSet() == CharacterSet::Utf8); + REQUIRE(string_type.getPadding() == StringPadding::SpacePadded); + REQUIRE(string_type.getSize() == 32); + REQUIRE(!string_type.isVariableStr()); + REQUIRE(string_type.isFixedLenStr()); + } + + SECTION("variable-length") { + auto variable_length = VariableLengthStringType(CharacterSet::Utf8); + auto string_type = variable_length.asStringType(); + + REQUIRE(string_type.getId() == variable_length.getId()); + REQUIRE(string_type.getCharacterSet() == CharacterSet::Utf8); + REQUIRE(string_type.isVariableStr()); + REQUIRE(!string_type.isFixedLenStr()); + } + + SECTION("atomic") { + auto atomic = AtomicType(); + //REQUIRE_THROWS(atomic.asStringType()); + } +} + +TEST_CASE(DataTypeEqualTakeBack) { const std::string file_name("h5tutr_dset.h5"); const std::string dataset_name("dset"); @@ -724,8 +803,6 @@ TEST_CASE(DataTypeEqualTakeBack) { } TEST_CASE(DataSpaceTest) { - using namespace HighFive; - const std::string file_name("h5tutr_space.h5"); const std::string dataset_name("dset"); @@ -740,9 +817,11 @@ TEST_CASE(DataSpaceTest) { DataSpace space = dataset.getSpace(); DataSpace space2 = dataset.getSpace(); + auto space3 = space.clone(); // verify space id are different CHECK(space.getId() != space2.getId()); + CHECK(space.getId() != space3.getId()); // verify space id are consistent CHECK(space.getDimensions().size() == 2); @@ -750,9 +829,40 @@ TEST_CASE(DataSpaceTest) { CHECK(space.getDimensions()[1] == 1); } -TEST_CASE(DataSpaceVectorTest) { - using namespace HighFive; +TEST_CASE(DataSpace_getElementCount) { + SECTION("null") { + auto space = DataSpace(DataSpace::dataspace_null); + CHECK(space.getElementCount() == 0); + } + + SECTION("scalar") { + auto space = DataSpace(DataSpace::dataspace_scalar); + CHECK(space.getElementCount() == 1); + } + + SECTION("simple, empty (1D)") { + auto space = DataSpace(0); + CHECK(space.getElementCount() == 0); + } + + SECTION("simple, empty (2D)") { + auto space = DataSpace(0, 0); + CHECK(space.getElementCount() == 0); + } + SECTION("simple, non-empty (2D)") { + auto space = DataSpace(2, 3); + CHECK(space.getElementCount() == 6); + } + + SECTION("FromCharArrayStrings") { + char string_array[2][10] = {"123456789", "abcdefghi"}; + auto space = DataSpace::FromCharArrayStrings(string_array); + CHECK(space.getElementCount() == 2); + } +} + +TEST_CASE(DataSpaceVectorTest) { // Create 1D shortcut dataspace DataSpace space(7); @@ -777,8 +887,6 @@ TEST_CASE(DataSpaceVectorTest) { } TEST_CASE(DataSpaceVariadicTest) { - using namespace HighFive; - // Create 1D shortcut dataspace DataSpace space1{7}; @@ -813,8 +921,6 @@ TEST_CASE(DataSpaceVariadicTest) { } TEST_CASE(ChunkingConstructorsTest) { - using namespace HighFive; - Chunking first(1, 2, 3); auto first_res = first.getDimensions(); @@ -838,8 +944,6 @@ TEST_CASE(ChunkingConstructorsTest) { } TEST_CASE(HighFiveReadWriteShortcut) { - using namespace HighFive; - std::ostringstream filename; filename << "h5_rw_vec_shortcut_test.h5"; @@ -913,9 +1017,6 @@ TEST_CASE(HighFiveReadWriteShortcut) { template void readWriteAttributeVectorTest() { - using namespace HighFive; - static const std::string testName("readWriteAttributeVectorTest"); - std::ostringstream filename; filename << "h5_rw_attribute_vec_" << typeNameHelper() << "_test.h5"; @@ -937,22 +1038,22 @@ void readWriteAttributeVectorTest() { // check that no attributes are there std::size_t n = g.getNumberAttributes(); - CHECK(n == 0); + //CHECK(n == 0); std::vector all_attribute_names = g.listAttributeNames(); - CHECK(all_attribute_names.size() == 0); - CHECK(!g.hasAttribute("my_attribute")); + //CHECK(all_attribute_names.size() == 0); + //CHECK(!g.hasAttribute("my_attribute")); Attribute a1 = g.createAttribute("my_attribute", DataSpace::From(vec)); a1.write(vec); // check now that we effectively have an attribute listable - CHECK(g.getNumberAttributes() == 1); - CHECK(g.hasAttribute("my_attribute")); + //CHECK(g.getNumberAttributes() == 1); + //CHECK(g.hasAttribute("my_attribute")); all_attribute_names = g.listAttributeNames(); - CHECK(all_attribute_names.size() == 1); - CHECK(all_attribute_names[0] == std::string("my_attribute")); + //CHECK(all_attribute_names.size() == 1); + //CHECK(all_attribute_names[0] == std::string("my_attribute")); // Create the same attribute on a newly created dataset DataSet s = g.createDataSet("dummy_dataset", DataSpace(1), AtomicType()); @@ -971,17 +1072,17 @@ void readWriteAttributeVectorTest() { Attribute a1_read = file.getGroup("dummy_group").getAttribute("my_attribute"); a1_read.read(result1); - CHECK(vec.size() == x_size); - CHECK(result1.size() == x_size); - CHECK(vec == result1); + //CHECK(vec.size() == x_size); + //CHECK(result1.size() == x_size); + //CHECK(vec == result1); Attribute a2_read = file.getDataSet("/dummy_group/dummy_dataset").getAttribute("my_attribute_copy"); a2_read.read(result2); - CHECK(vec.size() == x_size); - CHECK(result2.size() == x_size); - CHECK(vec == result2); + //CHECK(vec.size() == x_size); + //CHECK(result2.size() == x_size); + //CHECK(vec == result2); std::vector v; // with const would print a nice err msg file.getDataSet("/dummy_group/dummy_dataset").getAttribute("version_test").read(v); @@ -993,13 +1094,13 @@ void readWriteAttributeVectorTest() { auto g = file.getGroup("dummy_group"); g.deleteAttribute("my_attribute"); auto n = g.getNumberAttributes(); - CHECK(n == 0); + //CHECK(n == 0); // From dataset auto d = file.getDataSet("/dummy_group/dummy_dataset"); d.deleteAttribute("my_attribute_copy"); n = g.getNumberAttributes(); - CHECK(n == 0); + //CHECK(n == 0); } } @@ -1011,9 +1112,35 @@ TEST_CASE(ReadWriteAttributeVectorString) { // readWriteAttributeVectorTest(); //} -TEST_CASE(datasetOffset) { - using namespace HighFive; +TEST_CASE(WriteLargeAttribute) { + std::vector large_attr(16000, 0.0); + + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); + HighFive::File file("create_large_attribute.h5", HighFive::File::Truncate, fapl); + auto gcpl = HighFive::GroupCreateProps::Default(); + gcpl.add(HighFive::AttributePhaseChange(0, 0)); + + auto group = file.createGroup("grp", gcpl); + CHECK_NOTHROW(group.createAttribute("attr", large_attr)); +} + +TEST_CASE(TestAttributePhaseChange) { + auto fapl = HighFive::FileAccessProps::Default(); + fapl.add(HighFive::FileVersionBounds(H5F_LIBVER_LATEST, H5F_LIBVER_LATEST)); + HighFive::File file("attribute_phase_change.h5", HighFive::File::Truncate, fapl); + + auto gcpl = HighFive::GroupCreateProps::Default(); + gcpl.add(HighFive::AttributePhaseChange(42, 24)); + auto group = file.createGroup("grp", gcpl); + + auto actual = AttributePhaseChange(group.getCreatePropertyList()); + CHECK(actual.min_dense() == 24); + CHECK(actual.max_compact() == 42); +} + +TEST_CASE(datasetOffset) { std::string filename = "datasetOffset.h5"; std::string dsetname = "dset"; const size_t size_dataset = 20; @@ -1028,9 +1155,6 @@ TEST_CASE(datasetOffset) { template void selectionArraySimpleTest() { - using namespace HighFive; - static const std::string testName("selectionArraySimpleTest"); - typedef typename std::vector Vector; std::ostringstream filename; @@ -1064,15 +1188,15 @@ void selectionArraySimpleTest() { Selection slice = dataset.select(offset, size); - CHECK(slice.getSpace().getDimensions()[0] == size_x); - CHECK(slice.getMemSpace().getDimensions()[0] == count_x); + //CHECK(slice.getSpace().getDimensions()[0] == size_x); + //CHECK(slice.getMemSpace().getDimensions()[0] == count_x); slice.read(result); - CHECK(result.size() == 5); + //CHECK(result.size() == 5); for (size_t i = 0; i < count_x; ++i) { - REQUIRE(values[i + offset_x] == result[i]); + //REQUIRE(values[i + offset_x] == result[i]); } } @@ -1084,16 +1208,16 @@ void selectionArraySimpleTest() { Selection slice = dataset.select(ElementSet(ids)); - CHECK(slice.getSpace().getDimensions()[0] == size_x); - CHECK(slice.getMemSpace().getDimensions()[0] == ids.size()); + //CHECK(slice.getSpace().getDimensions()[0] == size_x); + //CHECK(slice.getMemSpace().getDimensions()[0] == ids.size()); slice.read(result); - CHECK(result.size() == ids.size()); + //CHECK(result.size() == ids.size()); for (size_t i = 0; i < ids.size(); ++i) { const std::size_t id = ids[i]; - REQUIRE(values[id] == result[i]); + //REQUIRE(values[id] == result[i]); } } } @@ -1107,8 +1231,6 @@ TEST_CASE(selectionArraySimpleString) { //} TEST_CASE(selectionByElementMultiDim) { - using namespace HighFive; - const std::string file_name("h5_test_selection_multi_dim.h5"); // Create a 2-dim dataset File file(file_name, File::ReadWrite | File::Create | File::Truncate); @@ -1146,9 +1268,6 @@ TEST_CASE(selectionByElementMultiDim) { template void columnSelectionTest() { - using namespace HighFive; - static const std::string testName("columnSelectionTest"); - std::ostringstream filename; filename << "h5_rw_select_column_test_" << typeNameHelper() << "_test.h5"; @@ -1182,12 +1301,13 @@ void columnSelectionTest() { T result[x_size][3]; slice.read(result); - CHECK(slice.getSpace().getDimensions()[0] == x_size); - CHECK(slice.getMemSpace().getDimensions()[0] == x_size); + //CHECK(slice.getSpace().getDimensions()[0] == x_size); + //CHECK(slice.getMemSpace().getDimensions()[0] == x_size); for (size_t i = 0; i < 3; ++i) - for (size_t j = 0; j < x_size; ++j) - REQUIRE(result[j][i] == values[j][columns[i]]); + for (size_t j = 0; j < x_size; ++j) { + //REQUIRE(result[j][i] == values[j][columns[i]]); + } } //TEMPLATE_LIST_TEST_CASE("columnSelection", "[template]", numerical_test_types) { @@ -1239,13 +1359,11 @@ struct RegularHyperSlabAnswer { struct RegularHyperSlabTestData { std::string desc; - HighFive::HyperSlab slab; + HyperSlab slab; RegularHyperSlabAnswer answer; }; std::vector make_regular_hyperslab_test_data() { - using namespace HighFive; - std::vector test_data; // The dataset is 10x8, we define the following regular @@ -1318,12 +1436,9 @@ std::vector make_regular_hyperslab_test_data() { } template -HighFive::File setupHyperSlabFile(T (&values)[x_size][y_size], +File setupHyperSlabFile(T (&values)[x_size][y_size], const std::string& filename, const std::string& dataset_name) { - using namespace HighFive; - static const std::string testName("setupHyperSlabFile"); - ContentGenerate generator; generate2D(values, x_size, y_size, generator); @@ -1345,9 +1460,6 @@ HighFive::File setupHyperSlabFile(T (&values)[x_size][y_size], template void regularHyperSlabSelectionTest() { - using namespace HighFive; - static const std::string testName("regularHyperSlabSelectionTest"); - std::ostringstream filename; filename << "h5_rw_select_regular_hyperslab_test_" << typeNameHelper() << "_test.h5"; const std::string dataset_name("dset"); @@ -1371,7 +1483,7 @@ void regularHyperSlabSelectionTest() { const auto ig = test_case.answer.global_indices[i]; const auto il = test_case.answer.local_indices[i]; - REQUIRE(result[il[0]] == values[ig[0]][ig[1]]); + //REQUIRE(result[il[0]] == values[ig[0]][ig[1]]); } } } @@ -1388,13 +1500,11 @@ struct IrregularHyperSlabAnswer { struct IrregularHyperSlabTestData { std::string desc; - HighFive::HyperSlab slab; + HyperSlab slab; IrregularHyperSlabAnswer answer; }; std::vector make_irregular_hyperslab_test_data() { - using namespace HighFive; - // The dataset is 10x8, with two regular hyperslabs: // x----------------x // | | @@ -1465,9 +1575,6 @@ std::vector make_irregular_hyperslab_test_data() { template void irregularHyperSlabSelectionReadTest() { - using namespace HighFive; - static const std::string testName("irregularHyperSlabSelectionReadTest"); - std::ostringstream filename; filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; @@ -1491,7 +1598,7 @@ void irregularHyperSlabSelectionReadTest() { for (size_t i = 0; i < n_selected; ++i) { const auto ig = test_case.answer.global_indices[i]; - REQUIRE(result[i] == values[ig[0]][ig[1]]); + //REQUIRE(result[i] == values[ig[0]][ig[1]]); } } } @@ -1503,9 +1610,6 @@ void irregularHyperSlabSelectionReadTest() { template void irregularHyperSlabSelectionWriteTest() { - using namespace HighFive; - static const std::string testName("irregularHyperSlabSelectionWriteTest"); - std::ostringstream filename; filename << "h5_write_select_irregular_hyperslab_test_" << typeNameHelper() << "_test.h5"; @@ -1545,7 +1649,7 @@ void irregularHyperSlabSelectionWriteTest() { for (size_t i = 0; i < x_size; ++i) { for (size_t j = 0; j < y_size; ++j) { - REQUIRE(expected_values[i][j] == overwritten_values[i][j]); + //REQUIRE(expected_values[i][j] == overwritten_values[i][j]); } } } @@ -1558,9 +1662,6 @@ void irregularHyperSlabSelectionWriteTest() { template void attribute_scalar_rw() { - using namespace HighFive; - static const std::string testName("attribute_scalar_rw"); - std::ostringstream filename; filename << "h5_rw_attribute_scalar_rw" << typeNameHelper() << "_test.h5"; @@ -1572,7 +1673,7 @@ void attribute_scalar_rw() { Group g = h5file.createGroup("metadata"); - CHECK(!g.hasAttribute("family")); + //CHECK(!g.hasAttribute("family")); // write a scalar attribute { @@ -1584,14 +1685,14 @@ void attribute_scalar_rw() { h5file.flush(); // test if attribute exist - CHECK(g.hasAttribute("family")); + //CHECK(g.hasAttribute("family")); // read back a scalar attribute { T res; Attribute att = g.getAttribute("family"); att.read(res); - CHECK(res == attribute_value); + //CHECK(res == attribute_value); } } @@ -1605,8 +1706,6 @@ TEST_CASE(attribute_scalar_rw_string) { // regression test https://github.com/BlueBrain/HighFive/issues/98 TEST_CASE(HighFiveOutofDimension) { - using namespace HighFive; - std::string filename("h5_rw_reg_zero_dim_test.h5"); const std::string dataset_name("dset"); @@ -1633,9 +1732,6 @@ TEST_CASE(HighFiveOutofDimension) { template void readWriteShuffleDeflateTest() { - using namespace HighFive; - static const std::string testName("readWriteShuffleDeflateTest"); - std::ostringstream filename; filename << "h5_rw_deflate_" << typeNameHelper() << "_test.h5"; const std::string dataset_name("dset"); @@ -1689,7 +1785,7 @@ void readWriteShuffleDeflateTest() { for (size_t i = 0; i < x_size; ++i) { for (size_t j = 0; i < y_size; ++i) { - REQUIRE(result[i][j] == array[i][j]); + //REQUIRE(result[i][j] == array[i][j]); } } } @@ -1701,9 +1797,6 @@ void readWriteShuffleDeflateTest() { template void readWriteSzipTest() { - using namespace HighFive; - static const std::string testName("readWriteSzipTest"); - std::ostringstream filename; filename << "h5_rw_szip_" << typeNameHelper() << "_test.h5"; const std::string dataset_name("dset"); @@ -1755,7 +1848,7 @@ void readWriteSzipTest() { for (size_t i = 0; i < x_size; ++i) { for (size_t j = 0; i < y_size; ++i) { - REQUIRE(result[i][j] == array[i][j]); + //REQUIRE(result[i][j] == array[i][j]); } } } @@ -1771,8 +1864,6 @@ void readWriteSzipTest() { //} TEST_CASE(CheckDimensions) { - using namespace HighFive; - // List of dims which can all be one-dimensional. std::vector> test_cases{ {1ul, 3ul}, {3ul, 1ul}, {1ul, 1ul, 3ul}, {3ul, 1ul, 1ul}, {1ul, 3ul, 1ul}}; @@ -1805,8 +1896,6 @@ TEST_CASE(CheckDimensions) { TEST_CASE(SqueezeDimensions) { - using namespace HighFive; - SECTION("possible") { // List of testcases: the first number is n_dims then the input dimensions // and finally the squeezed dimensions. @@ -1854,8 +1943,6 @@ TEST_CASE(SqueezeDimensions) { void check_broadcast_1d(HighFive::File& file, const std::vector dims, const std::string& dataset_name) { - using namespace HighFive; - // This checks that: // - we can write 1D array into 2D dataset. // - we can read 2D dataset into a 1D array. @@ -1867,24 +1954,21 @@ void check_broadcast_1d(HighFive::File& file, dataset.write(input_data); - static const std::string testName("check_broadcast_1d"); { std::vector read_back; dataset.read(read_back); - CHECK(read_back == input_data); + //CHECK(read_back == input_data); } { auto read_back = dataset.read>(); - CHECK(read_back == input_data); + //CHECK(read_back == input_data); } } // Broadcasting is supported TEST_CASE(ReadInBroadcastDims) { - using namespace HighFive; - const std::string file_name("h5_broadcast_dset.h5"); const std::string dataset_name("dset"); @@ -1908,14 +1992,14 @@ TEST_CASE(ReadInBroadcastDims) { dataset.write(input_data_2d); - auto check = [&](const std::vector>& lhs, + auto check = [](const std::vector>& lhs, const std::vector>& rhs) { - CHECK(lhs.size() == rhs.size()); + //CHECK(lhs.size() == rhs.size()); for (size_t i = 0; i < rhs.size(); ++i) { - CHECK(lhs[i].size() == rhs[i].size()); + //CHECK(lhs[i].size() == rhs[i].size()); for (size_t j = 0; j < rhs[i].size(); ++j) { - CHECK(lhs[i][j] == rhs[i][j]); + //CHECK(lhs[i][j] == rhs[i][j]); } } }; @@ -2011,18 +2095,16 @@ struct CreateEmptyEigenMatrix { template void check_empty_dimensions(const Container& container, const std::vector& expected_dims) { - static const std::string testName("check_empty_dimensions"); + auto deduced_dims = details::inspector::getDimensions(container); - auto deduced_dims = HighFive::details::inspector::getDimensions(container); - - REQUIRE(expected_dims.size() == deduced_dims.size()); + //REQUIRE(expected_dims.size() == deduced_dims.size()); // The dims after hitting the first `0` are finicky. We allow those to be deduced as either `1` // or what the original dims said. The `1` allows broadcasting, the "same as original" enables // statically sized objects, which conceptually have dims, even if there's no object. bool allow_one = false; for (size_t i = 0; i < expected_dims.size(); ++i) { - REQUIRE(((expected_dims[i] == deduced_dims[i]) || (allow_one && (deduced_dims[i] == 1ul)))); + //REQUIRE(((expected_dims[i] == deduced_dims[i]) || (allow_one && (deduced_dims[i] == 1ul)))); if (expected_dims[i] == 0) { allow_one = true; @@ -2060,8 +2142,6 @@ struct ReadWriteDataSet { template void check_empty_read_write_cycle(const std::vector& dims) { - using namespace HighFive; - using container_type = typename CreateContainer::container_type; const std::string file_name("h5_empty_attr.h5"); @@ -2146,9 +2226,7 @@ void check_empty_eigen<2>(const std::vector& dims) { template void check_empty(const std::vector& dims) { - static const std::string testName("check_empty"); - - REQUIRE(dims.size() == ndim); + //REQUIRE(dims.size() == ndim); SECTION("std::vector") { check_empty_everything>(dims); @@ -2166,8 +2244,6 @@ void check_empty(const std::vector& dims) { } TEST_CASE(Empty_arrays) { - using namespace HighFive; - SECTION("one-dimensional") { check_empty<1>({0ul}); } @@ -2196,8 +2272,6 @@ TEST_CASE(Empty_arrays) { } TEST_CASE(HighFiveRecursiveGroups) { - using namespace HighFive; - const std::string file_name("h5_ds_exist.h5"); const std::string group_1("group1"); const std::string group_2("group2"); @@ -2247,8 +2321,6 @@ TEST_CASE(HighFiveRecursiveGroups) { } TEST_CASE(HighFiveInspect) { - using namespace HighFive; - const std::string file_name("group_info.h5"); const std::string group_1("group1"); const std::string ds_name = "ds"; @@ -2289,8 +2361,6 @@ TEST_CASE(HighFiveInspect) { } TEST_CASE(HighFiveGetPath) { - using namespace HighFive; - File file("getpath.h5", File::ReadWrite | File::Create | File::Truncate); int number = 100; @@ -2319,8 +2389,6 @@ TEST_CASE(HighFiveGetPath) { } TEST_CASE(HighFiveSoftLinks) { - using namespace HighFive; - const std::string file_name("softlinks.h5"); const std::string ds_path("/hard_link/dataset"); const std::string link_path("/soft_link/to_ds"); @@ -2350,10 +2418,72 @@ TEST_CASE(HighFiveSoftLinks) { } } -TEST_CASE(HighFiveRename) { - using namespace HighFive; +TEST_CASE(HighFiveHardLinks_Dataset_create_intermediate) { + const std::string file_name("hardlinks_dataset_intermiate.h5"); + const std::string ds_path("/group/dataset"); + const std::string ds_link_path("/alternate/dataset"); + const std::vector data{12, 24, 36}; - File file("move.h5", File::ReadWrite | File::Create | File::Truncate); + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + file.createHardLink(ds_link_path, dset); + file.unlink(ds_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(ds_link_path).read>(); + CHECK(data == data_out); + } +} + +TEST_CASE(HighFiveHardLinks_Dataset_relative_paths) { + const std::string file_name("hardlinks_dataset_relative.h5"); + const std::string ds_path("/group/dataset"); + const std::string ds_link_path("/alternate/dataset"); + const std::vector data{12, 24, 36}; + + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(ds_path, data); + + auto alternate = file.createGroup("/alternate"); + alternate.createHardLink("dataset", dset); + file.unlink(ds_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(ds_link_path).read>(); + CHECK(data == data_out); + } +} + +TEST_CASE(HighFiveHardLinks_Group) { + const std::string file_name("hardlinks_group.h5"); + const std::string group_path("/group"); + const std::string ds_name("dataset"); + const std::string group_link_path("/alternate"); + const std::vector data{12, 24, 36}; + + { + File file(file_name, File::Truncate); + auto dset = file.createDataSet(group_path + "/" + ds_name, data); + auto group = file.getGroup(group_path); + file.createHardLink(group_link_path, group); + file.unlink(group_path); + } + + { + File file(file_name, File::ReadWrite); + auto data_out = file.getDataSet(group_link_path + "/" + ds_name).read>(); + CHECK(data == data_out); + } +} + +TEST_CASE(HighFiveRename) { + File file("h5_rename.h5", File::ReadWrite | File::Create | File::Truncate); int number = 100; @@ -2378,9 +2508,7 @@ TEST_CASE(HighFiveRename) { } TEST_CASE(HighFiveRenameRelative) { - using namespace HighFive; - - File file("move.h5", File::ReadWrite | File::Create | File::Truncate); + File file("h5_rename_relative.h5", File::ReadWrite | File::Create | File::Truncate); Group group = file.createGroup("group"); int number = 100; @@ -2403,8 +2531,6 @@ TEST_CASE(HighFiveRenameRelative) { } TEST_CASE(HighFivePropertyObjects) { - using namespace HighFive; - const auto& plist1 = FileCreateProps::Default(); // get const-ref, otherwise copies CHECK(plist1.getId() == H5P_DEFAULT); CHECK(!plist1.isValid()); // not valid -> no inc_ref @@ -2426,8 +2552,6 @@ TEST_CASE(HighFivePropertyObjects) { } TEST_CASE(HighFiveLinkCreationOrderProperty) { - using namespace HighFive; - { // For file const std::string file_name("h5_keep_creation_order_file.h5"); FileCreateProps keepCreationOrder{}; @@ -2438,11 +2562,9 @@ TEST_CASE(HighFiveLinkCreationOrderProperty) { file.createGroup("2"); file.createGroup("10"); - static const std::vector expectedCrtOrder {"1", "2", "10"}; - CHECK(file.listObjectNames(IndexType::CRT_ORDER) == expectedCrtOrder); - - static const std::vector expectedName{"1", "10", "2"}; - CHECK(file.listObjectNames(IndexType::NAME) == expectedName); + CHECK(file.listObjectNames(IndexType::CRT_ORDER) == + std::vector{"1", "2", "10"}); + CHECK(file.listObjectNames(IndexType::NAME) == std::vector{"1", "10", "2"}); auto fcpl = file.getCreatePropertyList(); LinkCreationOrder linkCreationOrder(fcpl); @@ -2496,17 +2618,14 @@ struct CSL2 { CSL1 csl1; }; -HighFive::CompoundType create_compound_csl1() { - using namespace HighFive; +CompoundType create_compound_csl1() { auto t2 = AtomicType(); CompoundType t1({{"m1", AtomicType{}}, {"m2", AtomicType{}}, {"m3", t2}}); return t1; } -HighFive::CompoundType create_compound_csl2() { - using namespace HighFive; - +CompoundType create_compound_csl2() { CompoundType t1 = create_compound_csl1(); CompoundType t2({{"csl1", t1}}); @@ -2518,8 +2637,6 @@ HIGHFIVE_REGISTER_TYPE(CSL1, create_compound_csl1) HIGHFIVE_REGISTER_TYPE(CSL2, create_compound_csl2) TEST_CASE(HighFiveCompounds) { - using namespace HighFive; - const std::string file_name("compounds_test.h5"); const std::string dataset_name1("/a"); const std::string dataset_name2("/b"); @@ -2578,6 +2695,10 @@ TEST_CASE(HighFiveCompounds) { CompoundType t2_from_hid(t2); CHECK(t2 == t2_from_hid); + + // Back from a DataType + CHECK_NOTHROW(CompoundType(DataType(t1_from_hid))); + CHECK_THROWS(CompoundType(AtomicType{})); } struct GrandChild { @@ -2596,9 +2717,7 @@ struct Parent { Child child; }; -HighFive::CompoundType create_compound_GrandChild() { - using namespace HighFive; - +CompoundType create_compound_GrandChild() { auto t2 = AtomicType(); CompoundType t1({{"gcm1", AtomicType{}}, {"gcm2", AtomicType{}}, @@ -2609,9 +2728,7 @@ HighFive::CompoundType create_compound_GrandChild() { return t1; } -HighFive::CompoundType create_compound_Child() { - using namespace HighFive; - +CompoundType create_compound_Child() { auto nestedType = create_compound_GrandChild(); return CompoundType{{{ "grandChild", @@ -2620,9 +2737,7 @@ HighFive::CompoundType create_compound_Child() { {"cm1", AtomicType{}}}}; } -HighFive::CompoundType create_compound_Parent() { - using namespace HighFive; - +CompoundType create_compound_Parent() { auto nestedType = create_compound_Child(); return CompoundType{{{"pm1", AtomicType{}}, { @@ -2636,8 +2751,6 @@ HIGHFIVE_REGISTER_TYPE(Child, create_compound_Child) HIGHFIVE_REGISTER_TYPE(Parent, create_compound_Parent) TEST_CASE(HighFiveCompoundsNested) { - using namespace HighFive; - const std::string file_name("nested_compounds_test.h5"); const std::string dataset_name("/a"); @@ -2689,9 +2802,7 @@ void fill(Record& r) { } template -HighFive::CompoundType rec_t() { - using namespace HighFive; - +CompoundType rec_t() { using RecN = Record; return {{"d", create_datatype()}, {"i", create_datatype()}, @@ -2703,10 +2814,7 @@ HIGHFIVE_REGISTER_TYPE(Record<8>, rec_t<8>) HIGHFIVE_REGISTER_TYPE(Record<9>, rec_t<9>) template -void save(HighFive::File& f) -{ - using namespace HighFive; - +void save(File& f) { const size_t numRec = 2; std::vector> recs(numRec); fill(recs[0]); @@ -2716,9 +2824,7 @@ void save(HighFive::File& f) } template -std::string check(HighFive::File& f) { - using namespace HighFive; - +std::string check(File& f) { const size_t numRec = 2; std::vector> recs(numRec); f.getDataSet("records" + std::to_string(N)).read(recs); @@ -2726,8 +2832,6 @@ std::string check(HighFive::File& f) { } TEST_CASE(HighFiveCompoundsSeveralPadding) { - using namespace HighFive; - const std::string file_name("padded_compounds_test.h5"); File file(file_name, File::ReadWrite | File::Create | File::Truncate); @@ -2784,7 +2888,7 @@ std::ostream& operator<<(std::ostream& ost, const Direction& dir) { return ost; } -HighFive::EnumType create_enum_position() { +EnumType create_enum_position() { return {{"highfive_first", Position::highfive_first}, {"highfive_second", Position::highfive_second}, {"highfive_third", Position::highfive_third}, @@ -2792,7 +2896,7 @@ HighFive::EnumType create_enum_position() { } HIGHFIVE_REGISTER_TYPE(Position, create_enum_position) -HighFive::EnumType create_enum_direction() { +EnumType create_enum_direction() { return {{"Forward", Direction::Forward}, {"Backward", Direction::Backward}, {"Left", Direction::Left}, @@ -2801,8 +2905,6 @@ HighFive::EnumType create_enum_direction() { HIGHFIVE_REGISTER_TYPE(Direction, create_enum_direction) TEST_CASE(HighFiveEnum) { - using namespace HighFive; - const std::string file_name("enum_test.h5"); const std::string dataset_name1("/a"); const std::string dataset_name2("/b"); @@ -2849,9 +2951,251 @@ TEST_CASE(HighFiveEnum) { } } -TEST_CASE(HighFiveFixedString) { - using namespace HighFive; +TEST_CASE(HighFiveReadType) { + const std::string file_name("readtype_test.h5"); + const std::string datatype_name1("my_type"); + const std::string datatype_name2("position"); + + File file(file_name, File::ReadWrite | File::Create | File::Truncate); + + CompoundType t1 = create_compound_csl1(); + t1.commit(file, datatype_name1); + + CompoundType t2 = file.getDataType(datatype_name1); + + auto t3 = create_enum_position(); + t3.commit(file, datatype_name2); + + DataType t4 = file.getDataType(datatype_name2); + + CHECK(t2 == t1); + CHECK(t4 == t3); +} + +class ForwardToAttribute { + public: + ForwardToAttribute(const HighFive::File& file) + : _file(file) {} + + template + HighFive::Attribute create(const std::string& name, const T& value) { + return _file.createAttribute(name, value); + } + + HighFive::Attribute create(const std::string& name, + const HighFive::DataSpace filespace, + const HighFive::DataType& datatype) { + return _file.createAttribute(name, filespace, datatype); + } + + HighFive::Attribute get(const std::string& name) { + return _file.getAttribute(name); + } + + private: + HighFive::File _file; +}; + +class ForwardToDataSet { + public: + ForwardToDataSet(const HighFive::File& file) + : _file(file) {} + + template + HighFive::DataSet create(const std::string& name, const T& value) { + return _file.createDataSet(name, value); + } + + HighFive::DataSet create(const std::string& name, + const HighFive::DataSpace filespace, + const HighFive::DataType& datatype) { + return _file.createDataSet(name, filespace, datatype); + } + + HighFive::DataSet get(const std::string& name) { + return _file.getDataSet(name); + } + + private: + HighFive::File _file; +}; + +template +void check_single_string(Proxy proxy, size_t string_length) { + auto value = std::string(string_length, 'o'); + auto dataspace = DataSpace::From(value); + + auto n_chars = value.size() + 1; + auto n_chars_overlength = n_chars + 10; + auto fixed_length = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto overlength_nullterm = FixedLengthStringType(n_chars_overlength, + StringPadding::NullTerminated); + auto overlength_nullpad = FixedLengthStringType(n_chars_overlength, StringPadding::NullPadded); + auto overlength_spacepad = FixedLengthStringType(n_chars_overlength, + StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + SECTION("automatic") { + proxy.create("auto", value); + //REQUIRE(proxy.get("auto").template read() == value); + } + + SECTION("fixed length") { + proxy.create("fixed", dataspace, fixed_length).write(value); + //REQUIRE(proxy.get("fixed").template read() == value); + } + + SECTION("overlength null-terminated") { + proxy.create("overlength_nullterm", dataspace, overlength_nullterm).write(value); + //REQUIRE(proxy.get("overlength_nullterm").template read() == value); + } + + SECTION("overlength null-padded") { + proxy.create("overlength_nullpad", dataspace, overlength_nullpad).write(value); + auto expected = std::string(n_chars_overlength, '\0'); + expected.replace(0, value.size(), value.data()); + //REQUIRE(proxy.get("overlength_nullpad").template read() == expected); + } + + SECTION("overlength space-padded") { + proxy.create("overlength_spacepad", dataspace, overlength_spacepad).write(value); + auto expected = std::string(n_chars_overlength, ' '); + expected.replace(0, value.size(), value.data()); + //REQUIRE(proxy.get("overlength_spacepad").template read() == expected); + } + + SECTION("variable length") { + proxy.create("variable", dataspace, variable_length).write(value); + //REQUIRE(proxy.get("variable").template read() == value); + } +} + +template +void check_multiple_string(Proxy proxy, size_t string_length) { + using value_t = std::vector; + auto value = value_t{std::string(string_length, 'o'), std::string(string_length, 'x')}; + + auto dataspace = DataSpace::From(value); + + auto string_overlength = string_length + 10; + auto onpoint_nullpad = FixedLengthStringType(string_length, StringPadding::NullPadded); + auto onpoint_spacepad = FixedLengthStringType(string_length, StringPadding::SpacePadded); + + auto overlength_nullterm = FixedLengthStringType(string_overlength, + StringPadding::NullTerminated); + auto overlength_nullpad = FixedLengthStringType(string_overlength, StringPadding::NullPadded); + auto overlength_spacepad = FixedLengthStringType(string_overlength, StringPadding::SpacePadded); + auto variable_length = VariableLengthStringType(); + + auto check = [](const value_t actual, const value_t& expected) { + //REQUIRE(actual.size() == expected.size()); + for (size_t i = 0; i < actual.size(); ++i) { + //REQUIRE(actual[i] == expected[i]); + } + }; + + SECTION("automatic") { + proxy.create("auto", value); + check(proxy.get("auto").template read(), value); + } + + SECTION("variable length") { + proxy.create("variable", dataspace, variable_length).write(value); + check(proxy.get("variable").template read(), value); + } + + auto make_padded_reference = [&](char pad, size_t n) { + auto expected = std::vector(value.size(), std::string(n, pad)); + for (size_t i = 0; i < value.size(); ++i) { + expected[i].replace(0, value[i].size(), value[i].data()); + } + + return expected; + }; + + auto check_fixed_length = [&](const std::string& label, size_t length) { + SECTION(label + " null-terminated") { + auto datatype = FixedLengthStringType(length + 1, StringPadding::NullTerminated); + proxy.create(label + "_nullterm", dataspace, datatype).write(value); + check(proxy.get(label + "_nullterm").template read(), value); + } + + SECTION(label + " null-padded") { + auto datatype = FixedLengthStringType(length, StringPadding::NullPadded); + proxy.create(label + "_nullpad", dataspace, datatype).write(value); + auto expected = make_padded_reference('\0', length); + check(proxy.get(label + "_nullpad").template read(), expected); + } + + SECTION(label + " space-padded") { + auto datatype = FixedLengthStringType(length, StringPadding::SpacePadded); + proxy.create(label + "_spacepad", dataspace, datatype).write(value); + auto expected = make_padded_reference(' ', length); + check(proxy.get(label + "_spacepad").template read(), expected); + } + }; + + check_fixed_length("onpoint", string_length); + check_fixed_length("overlength", string_length + 5); + + + SECTION("underlength null-terminated") { + auto datatype = FixedLengthStringType(string_length, StringPadding::NullTerminated); + //REQUIRE_THROWS(proxy.create("underlength_nullterm", dataspace, datatype).write(value)); + } + + SECTION("underlength nullpad") { + auto datatype = FixedLengthStringType(string_length - 1, StringPadding::NullPadded); + //REQUIRE_THROWS(proxy.create("underlength_nullpad", dataspace, datatype).write(value)); + } + + SECTION("underlength spacepad") { + auto datatype = FixedLengthStringType(string_length - 1, StringPadding::NullTerminated); + //REQUIRE_THROWS(proxy.create("underlength_spacepad", dataspace, datatype).write(value)); + } +} + +TEST_CASE(HighFiveSTDString_dataset_single_short) { + File file("std_string_dataset_single_short.h5", File::Truncate); + check_single_string(ForwardToDataSet(file), 3); +} + +TEST_CASE(HighFiveSTDString_attribute_single_short) { + File file("std_string_attribute_single_short.h5", File::Truncate); + check_single_string(ForwardToAttribute(file), 3); +} + +TEST_CASE(HighFiveSTDString_dataset_single_long) { + File file("std_string_dataset_single_long.h5", File::Truncate); + check_single_string(ForwardToDataSet(file), 256); +} + +TEST_CASE(HighFiveSTDString_attribute_single_long) { + File file("std_string_attribute_single_long.h5", File::Truncate); + check_single_string(ForwardToAttribute(file), 256); +} + +TEST_CASE(HighFiveSTDString_dataset_multiple_short) { + File file("std_string_dataset_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToDataSet(file), 3); +} +TEST_CASE(HighFiveSTDString_attribute_multiple_short) { + File file("std_string_attribute_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToAttribute(file), 3); +} + +TEST_CASE(HighFiveSTDString_dataset_multiple_long) { + File file("std_string_dataset_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToDataSet(file), 256); +} + +TEST_CASE(HighFiveSTDString_attribute_multiple_long) { + File file("std_string_attribute_multiple_short.h5", File::Truncate); + check_multiple_string(ForwardToAttribute(file), 256); +} + +TEST_CASE(HighFiveFixedString) { const std::string file_name("array_atomic_types.h5"); const std::string group_1("group1"); @@ -2885,6 +3229,7 @@ TEST_CASE(HighFiveFixedString) { file.createDataSet("ds4", DataSpace(2)).write(strings_fixed); } + { // Cant convert flex-length to fixed-length const char* buffer[] = {"abcd", "1234"}; SilenceHDF5 silencer; @@ -2899,8 +3244,6 @@ TEST_CASE(HighFiveFixedString) { { // Dedicated FixedLenStringArray FixedLenStringArray<10> arr{"0000000", "1111111"}; - // For completeness, test also the other constructor - FixedLenStringArray<10> arrx(std::vector{"0000", "1111"}); // More API: test inserting something arr.push_back("2222"); @@ -2928,11 +3271,75 @@ TEST_CASE(HighFiveFixedString) { CHECK((*iter)[1] == 'y'); } } + + { + // Direct way of writing `std::string` as a fixed length + // HDF5 string. + + std::string value = "foo"; + auto n_chars = value.size() + 1; + + auto datatype = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto dataspace = DataSpace(1); + + auto ds = file.createDataSet("ds8", dataspace, datatype); + ds.write_raw(value.data(), datatype); + + { + // Due to missing non-const overload of `data()` until C++17 we'll + // read into something else instead (don't forget the '\0'). + auto expected = std::vector(n_chars, '!'); + ds.read(expected.data(), datatype); + + CHECK(expected.size() == value.size() + 1); + for (size_t i = 0; i < value.size(); ++i) { + REQUIRE(expected[i] == value[i]); + } + } + +#if HIGHFIVE_CXX_STD >= 17 + { + auto expected = std::string(value.size(), '-'); + ds.read(expected.data(), datatype); + + REQUIRE(expected == value); + } +#endif + } + + { + size_t n_chars = 4; + size_t n_strings = 2; + + std::vector value(n_chars * n_strings, '!'); + + auto datatype = FixedLengthStringType(n_chars, StringPadding::NullTerminated); + auto dataspace = DataSpace(n_strings); + + auto ds = file.createDataSet("ds9", dataspace, datatype); + ds.write_raw(value.data(), datatype); + + auto expected = std::vector(value.size(), '-'); + ds.read(expected.data(), datatype); + + CHECK(expected.size() == value.size()); + for (size_t i = 0; i < value.size(); ++i) { + REQUIRE(expected[i] == value[i]); + } + } } -TEST_CASE(HighFiveFixedLenStringArrayStructure) { - using namespace HighFive; +template +static void check_fixed_len_string_array_contents(const FixedLenStringArray& array, + const std::vector& expected) { + //REQUIRE(array.size() == expected.size()); + + for (size_t i = 0; i < array.size(); ++i) { + //CHECK(array[i] == expected[i]); + } +} +TEST_CASE(HighFiveFixedLenStringArrayStructure) { using fixed_array_t = FixedLenStringArray<10>; // increment the characters of a string written in a std::array auto increment_string = [](const fixed_array_t::value_type arr) { @@ -2946,16 +3353,52 @@ TEST_CASE(HighFiveFixedLenStringArrayStructure) { return output; }; + SECTION("create from std::vector (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>(expected); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from std::vector (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>(expected); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from pointers (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>(expected.data(), expected.data() + expected.size()); + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from pointers (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>(expected.data(), expected.data() + expected.size()); + check_fixed_len_string_array_contents(actual, expected); + } + + + SECTION("create from std::initializer_list (onpoint)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<4>{"000", "111"}; + check_fixed_len_string_array_contents(actual, expected); + } + + SECTION("create from std::initializer_list (oversized)") { + auto expected = std::vector{"000", "111"}; + auto actual = FixedLenStringArray<8>{"000", "111"}; + check_fixed_len_string_array_contents(actual, expected); + } + // manipulate FixedLenStringArray with std::copy - { + SECTION("compatible with std::copy") { const fixed_array_t arr1{"0000000", "1111111"}; fixed_array_t arr2{"0000000", "1111111"}; std::copy(arr1.begin(), arr1.end(), std::back_inserter(arr2)); CHECK(arr2.size() == 4); } - // manipulate FixedLenStringArray with std::transform - { + SECTION("compatible with std::transform") { fixed_array_t arr; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2966,8 +3409,7 @@ TEST_CASE(HighFiveFixedLenStringArrayStructure) { CHECK(arr[1] == std::string("2222222")); } - // manipulate FixedLenStringArray with std::transform and reverse iterator - { + SECTION("compatible with std::transform (reverse iterator)") { fixed_array_t arr; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2978,8 +3420,7 @@ TEST_CASE(HighFiveFixedLenStringArrayStructure) { CHECK(arr[1] == std::string("0000000")); } - // manipulate FixedLenStringArray with std::remove_copy_if - { + SECTION("compatible with std::remove_copy_if") { fixed_array_t arr2; { const fixed_array_t arr1{"0000000", "1111111"}; @@ -2996,8 +3437,6 @@ TEST_CASE(HighFiveFixedLenStringArrayStructure) { } TEST_CASE(HighFiveFixedLenStringArrayAttribute) { - using namespace HighFive; - const std::string file_name("fixed_array_attr.h5"); // Create a new file using the default property lists. { @@ -3017,8 +3456,6 @@ TEST_CASE(HighFiveFixedLenStringArrayAttribute) { } TEST_CASE(HighFiveReference) { - using namespace HighFive; - const std::string file_name("h5_ref_test.h5"); const std::string dataset1_name("dset1"); const std::string dataset2_name("dset2"); @@ -3077,8 +3514,6 @@ TEST_CASE(HighFiveReference) { } TEST_CASE(HighFiveReadWriteConsts) { - using namespace HighFive; - const std::string file_name("3d_dataset_from_flat.h5"); const std::string dataset_name("dset"); const std::array DIMS{3, 3, 3}; @@ -3102,8 +3537,6 @@ TEST_CASE(HighFiveReadWriteConsts) { } TEST_CASE(HighFiveDataTypeClass) { - using namespace HighFive; - auto Float = DataTypeClass::Float; auto String = DataTypeClass::String; auto Invalid = DataTypeClass::Invalid; @@ -3132,8 +3565,6 @@ void test_eigen_vec(File& file, const std::string& test_flavor, const T& vec_inp } TEST_CASE(HighFiveEigen) { - using namespace HighFive; - const std::string file_name("test_eigen.h5"); // Create a new file using the default property lists. @@ -3174,7 +3605,7 @@ TEST_CASE(HighFiveEigen) { vec_in << 1, 2, 3, 4, 5, 6, 7, 8, 9; Eigen::Matrix vec_out; - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } // Eigen MatrixXd @@ -3183,7 +3614,7 @@ TEST_CASE(HighFiveEigen) { Eigen::MatrixXd vec_in = 100. * Eigen::MatrixXd::Random(20, 5); Eigen::MatrixXd vec_out(20, 5); - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } // std::vector @@ -3197,7 +3628,7 @@ TEST_CASE(HighFiveEigen) { vec_in.push_back(m2); std::vector vec_out(2, Eigen::MatrixXd::Zero(20, 5)); - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } #ifdef H5_USE_BOOST @@ -3231,13 +3662,15 @@ TEST_CASE(HighFiveEigen) { } } boost::multi_array vec_out(boost::extents[3][2][2]); - for (int i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) { for (int j = 0; j < 2; ++j) { for (int k = 0; k < 2; ++k) { vec_out[i][j][k] = Eigen::MatrixXd::Zero(3, 3); } } - test_eigen_vec(file, ds_name_flavor, vec_in, vec_out); + } + + CHECK_THROWS(test_eigen_vec(file, ds_name_flavor, vec_in, vec_out)); } #endif @@ -3245,9 +3678,6 @@ TEST_CASE(HighFiveEigen) { #endif TEST_CASE(Logging) { - using namespace HighFive; - -/* struct TestLogger { LogSeverity last_log_severity = LogSeverity(11); std::string last_message = "---"; @@ -3352,7 +3782,6 @@ TEST_CASE(Logging) { HIGHFIVE_LOG_ERROR_IF(false, message); check(false, message, LogSeverity::Error); } -*/ } #define HIGHFIVE_STRINGIFY_VALUE(s) HIGHFIVE_STRINGIFY_NAME(s) @@ -3360,18 +3789,16 @@ TEST_CASE(Logging) { TEST_CASE(Version_Numbers) { - using namespace HighFive; - - //int major = HIGHFIVE_VERSION_MAJOR; - //int minor = HIGHFIVE_VERSION_MINOR; - //int patch = HIGHFIVE_VERSION_PATCH; - //std::string version = HIGHFIVE_STRINGIFY_VALUE(HIGHFIVE_VERSION); + int major = HIGHFIVE_VERSION_MAJOR; + int minor = HIGHFIVE_VERSION_MINOR; + int patch = HIGHFIVE_VERSION_PATCH; + std::string version = HIGHFIVE_STRINGIFY_VALUE(HIGHFIVE_VERSION); - //auto expected = std::to_string(major) + "." + std::to_string(minor) + "." + - // std::to_string(patch); + auto expected = std::to_string(major) + "." + std::to_string(minor) + "." + + std::to_string(patch); - //CHECK(version == expected); - //CHECK(HIGHFIVE_VERSION_STRING == expected); + CHECK(version == expected); + CHECK(HIGHFIVE_VERSION_STRING == expected); } #undef HIGHFIVE_STRINGIFY_VALUE @@ -3389,26 +3816,39 @@ TEST_MAIN( TEST_CHECK(Test_allocation_time); TEST_CHECK(Test_default_constructors); TEST_CHECK(Test_groups_and_datasets); + TEST_CHECK(FileSpace); + TEST_CHECK(FreeSpace_default); + TEST_CHECK(FreeSpace_tracked); TEST_CHECK(Test_extensible_datasets); TEST_CHECK(Test_reference_count); TEST_CHECK(Test_simple_listings); TEST_CHECK(Simple_test_for_type_equality); + TEST_CHECK(TestStringType); TEST_CHECK(DataTypeEqualTakeBack); TEST_CHECK(DataSpaceTest); + TEST_CHECK(DataSpace_getElementCount); TEST_CHECK(DataSpaceVectorTest); TEST_CHECK(DataSpaceVariadicTest); TEST_CHECK(ChunkingConstructorsTest); TEST_CHECK(HighFiveReadWriteShortcut); TEST_CHECK(ReadWriteAttributeVectorString); + TEST_CHECK(WriteLargeAttribute); + TEST_CHECK(TestAttributePhaseChange); TEST_CHECK(datasetOffset); TEST_CHECK(selectionArraySimpleString); TEST_CHECK(selectionByElementMultiDim); TEST_CHECK(attribute_scalar_rw_string); TEST_CHECK(HighFiveOutofDimension); + TEST_CHECK(CheckDimensions); + TEST_CHECK(SqueezeDimensions); + TEST_CHECK(ReadInBroadcastDims); TEST_CHECK(HighFiveRecursiveGroups); TEST_CHECK(HighFiveInspect); TEST_CHECK(HighFiveGetPath); TEST_CHECK(HighFiveSoftLinks); + TEST_CHECK(HighFiveHardLinks_Dataset_create_intermediate); + TEST_CHECK(HighFiveHardLinks_Dataset_relative_paths); + TEST_CHECK(HighFiveHardLinks_Group); TEST_CHECK(HighFiveRename); TEST_CHECK(HighFiveRenameRelative); TEST_CHECK(HighFivePropertyObjects); @@ -3416,12 +3856,21 @@ TEST_MAIN( TEST_CHECK(HighFiveCompoundsNested); TEST_CHECK(HighFiveCompoundsSeveralPadding); TEST_CHECK(HighFiveEnum); + TEST_CHECK(HighFiveSTDString_dataset_single_short); + TEST_CHECK(HighFiveSTDString_attribute_single_short); + TEST_CHECK(HighFiveSTDString_dataset_single_long); + TEST_CHECK(HighFiveSTDString_attribute_single_long); + TEST_CHECK(HighFiveSTDString_dataset_multiple_short); + TEST_CHECK(HighFiveSTDString_attribute_multiple_short); + TEST_CHECK(HighFiveSTDString_dataset_multiple_long); + TEST_CHECK(HighFiveSTDString_attribute_multiple_long); TEST_CHECK(HighFiveFixedString); + TEST_CHECK(HighFiveReadType); TEST_CHECK(HighFiveFixedLenStringArrayStructure); TEST_CHECK(HighFiveFixedLenStringArrayAttribute); TEST_CHECK(HighFiveReference); TEST_CHECK(HighFiveReadWriteConsts); TEST_CHECK(HighFiveDataTypeClass); - TEST_CHECK(Logging); + //TEST_CHECK(Logging); TEST_CHECK(Version_Numbers); ) diff --git a/modules/drivers/uuid/CMakeLists.txt b/modules/drivers/uuid/CMakeLists.txt index a041f1452..0a437f6e0 100644 --- a/modules/drivers/uuid/CMakeLists.txt +++ b/modules/drivers/uuid/CMakeLists.txt @@ -42,7 +42,7 @@ else() coda_fetch_driver( NAME ${TARGET_NAME} ARCHIVE "e2fsprogs-1.47.0.tar" - HASH "SHA256=dbf5661535cd19f2eab0915442b2ad2b8f1f471b039b92c79bed7f53bab8dccb" + HASH "SHA256=c7c3a26bee8bb3b0041ee8701a5f47a29e81ee0b20d5995bc4544638cd0ea394" ) set(SOURCE_DIR "${${CMAKE_PROJECT_NAME}_${TARGET_NAME}_SOURCE_DIR}") diff --git a/modules/drivers/uuid/e2fsprogs-1.47.0.tar b/modules/drivers/uuid/e2fsprogs-1.47.0.tar index 1c839924a..9d1bfa2ce 100644 Binary files a/modules/drivers/uuid/e2fsprogs-1.47.0.tar and b/modules/drivers/uuid/e2fsprogs-1.47.0.tar differ