mirror of
https://git.gfz-potsdam.de/naaice/poet.git
synced 2025-12-15 12:28:22 +01:00
computeStats not working correctly, Unit Tests added
This commit is contained in:
parent
12d39ecb9b
commit
0cc0c9cdf6
@ -28,12 +28,12 @@ if (POET_PREPROCESS_BENCHS)
|
||||
endif()
|
||||
|
||||
# as tug will also pull in doctest as a dependency
|
||||
set(TUG_ENABLE_TESTING OFF CACHE BOOL "" FORCE)
|
||||
set(TUG_ENABLE_TESTING ON CACHE BOOL "" FORCE)
|
||||
|
||||
add_subdirectory(ext/tug EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(ext/iphreeqc EXCLUDE_FROM_ALL)
|
||||
|
||||
option(POET_ENABLE_TESTING "Build test suite for POET" OFF)
|
||||
option(POET_ENABLE_TESTING "Build test suite for POET" ON)
|
||||
|
||||
if (POET_ENABLE_TESTING)
|
||||
add_subdirectory(test)
|
||||
|
||||
7106
include/doctest/doctest.h
Normal file
7106
include/doctest/doctest.h
Normal file
File diff suppressed because it is too large
Load Diff
169
include/doctest/extensions/doctest_mpi.h
Normal file
169
include/doctest/extensions/doctest_mpi.h
Normal file
@ -0,0 +1,169 @@
|
||||
#ifndef DOCTEST_MPI_H
|
||||
#define DOCTEST_MPI_H
|
||||
|
||||
#ifdef DOCTEST_CONFIG_IMPLEMENT
|
||||
|
||||
#include "doctest/extensions/mpi_sub_comm.h"
|
||||
#include "mpi_reporter.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace doctest {
|
||||
|
||||
// Each time a MPI_TEST_CASE is executed on N procs,
|
||||
// we need a sub-communicator of N procs to execute it.
|
||||
// It is then registered here and can be re-used
|
||||
// by other tests that requires a sub-comm of the same size
|
||||
std::unordered_map<int,mpi_sub_comm> sub_comms_by_size;
|
||||
|
||||
// Record if at least one MPI_TEST_CASE was registered "skipped"
|
||||
// because there is not enought procs to execute it
|
||||
int nb_test_cases_skipped_insufficient_procs = 0;
|
||||
|
||||
|
||||
std::string thread_level_to_string(int thread_lvl);
|
||||
int mpi_init_thread(int argc, char *argv[], int required_thread_support);
|
||||
void mpi_finalize();
|
||||
|
||||
|
||||
// Can be safely called before MPI_Init()
|
||||
// This is needed for MPI_TEST_CASE because we use doctest::skip()
|
||||
// to prevent execution of tests where there is not enough procs,
|
||||
// but doctest::skip() is called during test registration, that is, before main(), and hence before MPI_Init()
|
||||
int mpi_comm_world_size() {
|
||||
#if defined(OPEN_MPI)
|
||||
const char* size_str = std::getenv("OMPI_COMM_WORLD_SIZE");
|
||||
#elif defined(I_MPI_VERSION) || defined(MPI_VERSION) // Intel MPI + MPICH (at least)
|
||||
const char* size_str = std::getenv("PMI_SIZE"); // see https://community.intel.com/t5/Intel-oneAPI-HPC-Toolkit/Environment-variables-defined-by-intel-mpirun/td-p/1096703
|
||||
#else
|
||||
#error "Unknown MPI implementation: please submit an issue or a PR to doctest. Meanwhile, you can look at the output of e.g. `mpirun -np 3 env` to search for an environnement variable that contains the size of MPI_COMM_WORLD and extend this code accordingly"
|
||||
#endif
|
||||
if (size_str==nullptr) return 1; // not launched with mpirun/mpiexec, so assume only one process
|
||||
return std::stoi(size_str);
|
||||
}
|
||||
|
||||
// Record size of MPI_COMM_WORLD with mpi_comm_world_size()
|
||||
int world_size_before_init = mpi_comm_world_size();
|
||||
|
||||
|
||||
std::string thread_level_to_string(int thread_lvl) {
|
||||
switch (thread_lvl) {
|
||||
case MPI_THREAD_SINGLE: return "MPI_THREAD_SINGLE";
|
||||
case MPI_THREAD_FUNNELED: return "MPI_THREAD_FUNNELED";
|
||||
case MPI_THREAD_SERIALIZED: return "MPI_THREAD_SERIALIZED";
|
||||
case MPI_THREAD_MULTIPLE: return "MPI_THREAD_MULTIPLE";
|
||||
default: return "Invalid MPI thread level";
|
||||
}
|
||||
}
|
||||
int mpi_init_thread(int argc, char *argv[], int required_thread_support) {
|
||||
int provided_thread_support;
|
||||
MPI_Init_thread(&argc, &argv, required_thread_support, &provided_thread_support);
|
||||
|
||||
int world_size;
|
||||
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
|
||||
if (world_size_before_init != world_size) {
|
||||
DOCTEST_INTERNAL_ERROR(
|
||||
"doctest found "+std::to_string(world_size_before_init)+" MPI processes before `MPI_Init_thread`,"
|
||||
" but MPI_COMM_WORLD is actually of size "+std::to_string(world_size)+".\n"
|
||||
"This is most likely due to your MPI implementation not being well supported by doctest. Please report this issue on GitHub"
|
||||
);
|
||||
}
|
||||
|
||||
if (provided_thread_support!=required_thread_support) {
|
||||
std::cout <<
|
||||
"WARNING: " + thread_level_to_string(required_thread_support) + " was asked, "
|
||||
+ "but only " + thread_level_to_string(provided_thread_support) + " is provided by the MPI library\n";
|
||||
}
|
||||
return provided_thread_support;
|
||||
}
|
||||
void mpi_finalize() {
|
||||
// We need to destroy all created sub-communicators before calling MPI_Finalize()
|
||||
doctest::sub_comms_by_size.clear();
|
||||
MPI_Finalize();
|
||||
}
|
||||
|
||||
} // doctest
|
||||
|
||||
#else // DOCTEST_CONFIG_IMPLEMENT
|
||||
|
||||
#include "doctest/extensions/mpi_sub_comm.h"
|
||||
#include <unordered_map>
|
||||
#include <exception>
|
||||
|
||||
namespace doctest {
|
||||
|
||||
extern std::unordered_map<int,mpi_sub_comm> sub_comms_by_size;
|
||||
extern int nb_test_cases_skipped_insufficient_procs;
|
||||
extern int world_size_before_init;
|
||||
int mpi_comm_world_size();
|
||||
|
||||
int mpi_init_thread(int argc, char *argv[], int required_thread_support);
|
||||
void mpi_finalize();
|
||||
|
||||
template<int nb_procs, class F>
|
||||
void execute_mpi_test_case(F func) {
|
||||
auto it = sub_comms_by_size.find(nb_procs);
|
||||
if (it==end(sub_comms_by_size)) {
|
||||
bool was_emplaced = false;
|
||||
std::tie(it,was_emplaced) = sub_comms_by_size.emplace(std::make_pair(nb_procs,mpi_sub_comm(nb_procs)));
|
||||
assert(was_emplaced);
|
||||
}
|
||||
const mpi_sub_comm& sub = it->second;
|
||||
if (sub.comm != MPI_COMM_NULL) {
|
||||
func(sub.rank,nb_procs,sub.comm,std::integral_constant<int,nb_procs>{});
|
||||
};
|
||||
}
|
||||
|
||||
inline bool
|
||||
insufficient_procs(int test_nb_procs) {
|
||||
static const int world_size = mpi_comm_world_size();
|
||||
bool insufficient = test_nb_procs>world_size;
|
||||
if (insufficient) {
|
||||
++nb_test_cases_skipped_insufficient_procs;
|
||||
}
|
||||
return insufficient;
|
||||
}
|
||||
|
||||
} // doctest
|
||||
|
||||
|
||||
#define DOCTEST_MPI_GEN_ASSERTION(rank_to_test, assertion, ...) \
|
||||
static_assert(rank_to_test<test_nb_procs_as_int_constant.value,"Trying to assert on a rank greater than the number of procs of the test!"); \
|
||||
if(rank_to_test == test_rank) assertion(__VA_ARGS__)
|
||||
|
||||
#define DOCTEST_MPI_WARN(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_WARN,__VA_ARGS__)
|
||||
#define DOCTEST_MPI_CHECK(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_CHECK,__VA_ARGS__)
|
||||
#define DOCTEST_MPI_REQUIRE(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_REQUIRE,__VA_ARGS__)
|
||||
#define DOCTEST_MPI_WARN_FALSE(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_WARN_FALSE,__VA_ARGS__)
|
||||
#define DOCTEST_MPI_CHECK_FALSE(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_CHECK_FALSE,__VA_ARGS__)
|
||||
#define DOCTEST_MPI_REQUIRE_FALSE(rank_to_test, ...) DOCTEST_MPI_GEN_ASSERTION(rank_to_test,DOCTEST_REQUIRE_FALSE,__VA_ARGS__)
|
||||
|
||||
#define DOCTEST_CREATE_MPI_TEST_CASE(name,nb_procs,func) \
|
||||
static void func(DOCTEST_UNUSED int test_rank, DOCTEST_UNUSED int test_nb_procs, DOCTEST_UNUSED MPI_Comm test_comm, DOCTEST_UNUSED std::integral_constant<int,nb_procs>); \
|
||||
TEST_CASE(name * doctest::description("MPI_TEST_CASE") * doctest::skip(doctest::insufficient_procs(nb_procs))) { \
|
||||
doctest::execute_mpi_test_case<nb_procs>(func); \
|
||||
} \
|
||||
static void func(DOCTEST_UNUSED int test_rank, DOCTEST_UNUSED int test_nb_procs, DOCTEST_UNUSED MPI_Comm test_comm, DOCTEST_UNUSED std::integral_constant<int,nb_procs> test_nb_procs_as_int_constant)
|
||||
// DOC: test_rank, test_nb_procs, and test_comm are available UNDER THESE SPECIFIC NAMES in the body of the unit test
|
||||
// DOC: test_nb_procs_as_int_constant is equal to test_nb_procs, but as a compile time value
|
||||
// (used in CHECK-like macros to assert the checked rank exists)
|
||||
|
||||
#define DOCTEST_MPI_TEST_CASE(name,nb_procs) \
|
||||
DOCTEST_CREATE_MPI_TEST_CASE(name,nb_procs,DOCTEST_ANONYMOUS(DOCTEST_MPI_FUNC))
|
||||
|
||||
|
||||
// == SHORT VERSIONS OF THE MACROS
|
||||
#if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES)
|
||||
#define MPI_WARN DOCTEST_MPI_WARN
|
||||
#define MPI_CHECK DOCTEST_MPI_CHECK
|
||||
#define MPI_REQUIRE DOCTEST_MPI_REQUIRE
|
||||
#define MPI_WARN_FALSE DOCTEST_MPI_WARN_FALSE
|
||||
#define MPI_CHECK_FALSE DOCTEST_MPI_CHECK_FALSE
|
||||
#define MPI_REQUIRE_FALSE DOCTEST_MPI_REQUIRE_FALSE
|
||||
|
||||
#define MPI_TEST_CASE DOCTEST_MPI_TEST_CASE
|
||||
#endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES
|
||||
|
||||
|
||||
#endif // DOCTEST_CONFIG_IMPLEMENT
|
||||
|
||||
#endif // DOCTEST_MPI_H
|
||||
37
include/doctest/extensions/doctest_util.h
Normal file
37
include/doctest/extensions/doctest_util.h
Normal file
@ -0,0 +1,37 @@
|
||||
//
|
||||
// doctest_util.h - an accompanying extensions header to the main doctest.h header
|
||||
//
|
||||
// Copyright (c) 2016-2023 Viktor Kirilov
|
||||
//
|
||||
// Distributed under the MIT Software License
|
||||
// See accompanying file LICENSE.txt or copy at
|
||||
// https://opensource.org/licenses/MIT
|
||||
//
|
||||
// The documentation can be found at the library's page:
|
||||
// https://github.com/doctest/doctest/blob/master/doc/markdown/readme.md
|
||||
//
|
||||
|
||||
#ifndef DOCTEST_UTIL_H
|
||||
#define DOCTEST_UTIL_H
|
||||
|
||||
#ifndef DOCTEST_LIBRARY_INCLUDED
|
||||
#include "../doctest.h"
|
||||
#endif
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace doctest {
|
||||
|
||||
inline void applyCommandLine(doctest::Context& ctx, const std::vector<std::string>& args) {
|
||||
auto doctest_args = std::make_unique<const char*[]>(args.size());
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
doctest_args[i] = args[i].c_str();
|
||||
}
|
||||
ctx.applyCommandLine(args.size(), doctest_args.get());
|
||||
}
|
||||
|
||||
} // namespace doctest
|
||||
|
||||
#endif // DOCTEST_UTIL_H
|
||||
271
include/doctest/extensions/mpi_reporter.h
Normal file
271
include/doctest/extensions/mpi_reporter.h
Normal file
@ -0,0 +1,271 @@
|
||||
#ifndef DOCTEST_MPI_REPORTER_H
|
||||
#define DOCTEST_MPI_REPORTER_H
|
||||
|
||||
// #include <doctest/doctest.h>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
#include "mpi.h"
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
|
||||
namespace doctest {
|
||||
|
||||
extern int nb_test_cases_skipped_insufficient_procs;
|
||||
int mpi_comm_world_size();
|
||||
|
||||
namespace {
|
||||
|
||||
// https://stackoverflow.com/a/11826666/1583122
|
||||
struct NullBuffer : std::streambuf {
|
||||
int overflow(int c) { return c; }
|
||||
};
|
||||
class NullStream : public std::ostream {
|
||||
public:
|
||||
NullStream()
|
||||
: std::ostream(&nullBuff)
|
||||
{}
|
||||
private:
|
||||
NullBuffer nullBuff = {};
|
||||
};
|
||||
static NullStream nullStream;
|
||||
|
||||
|
||||
/* \brief Extends the ConsoleReporter of doctest
|
||||
* Each process writes its results to its own file
|
||||
* Intended to be used when a test assertion fails and the user wants to know exactly what happens on which process
|
||||
*/
|
||||
struct MpiFileReporter : public ConsoleReporter {
|
||||
std::ofstream logfile_stream = {};
|
||||
|
||||
MpiFileReporter(const ContextOptions& co)
|
||||
: ConsoleReporter(co,logfile_stream)
|
||||
{
|
||||
int rank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
|
||||
std::string logfile_name = "doctest_" + std::to_string(rank) + ".log";
|
||||
|
||||
logfile_stream = std::ofstream(logfile_name.c_str(), std::fstream::out);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* \brief Extends the ConsoleReporter of doctest
|
||||
* Allows to manage the execution of tests in a parallel framework
|
||||
* All results are collected on rank 0
|
||||
*/
|
||||
struct MpiConsoleReporter : public ConsoleReporter {
|
||||
private:
|
||||
static std::ostream& replace_by_null_if_not_rank_0(std::ostream* os) {
|
||||
int rank = 0;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
if (rank==0) {
|
||||
return *os;
|
||||
} else {
|
||||
return nullStream;
|
||||
}
|
||||
}
|
||||
std::vector<std::pair<std::string, int>> m_failure_str_queue = {};
|
||||
public:
|
||||
MpiConsoleReporter(const ContextOptions& co)
|
||||
: ConsoleReporter(co,replace_by_null_if_not_rank_0(co.cout))
|
||||
{}
|
||||
|
||||
std::string file_line_to_string(const char* file, int line,
|
||||
const char* tail = ""){
|
||||
std::stringstream ss;
|
||||
ss << skipPathFromFilename(file)
|
||||
<< (opt.gnu_file_line ? ":" : "(")
|
||||
<< (opt.no_line_numbers ? 0 : line) // 0 or the real num depending on the option
|
||||
<< (opt.gnu_file_line ? ":" : "):") << tail;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void test_run_end(const TestRunStats& p) override {
|
||||
ConsoleReporter::test_run_end(p);
|
||||
|
||||
const bool anythingFailed = p.numTestCasesFailed > 0 || p.numAssertsFailed > 0;
|
||||
|
||||
// -----------------------------------------------------
|
||||
// > Gather information in rank 0
|
||||
int n_rank, rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &n_rank);
|
||||
|
||||
int g_numAsserts = 0;
|
||||
int g_numAssertsFailed = 0;
|
||||
int g_numTestCasesFailed = 0;
|
||||
|
||||
MPI_Reduce(&p.numAsserts , &g_numAsserts , 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
|
||||
MPI_Reduce(&p.numAssertsFailed , &g_numAssertsFailed , 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
|
||||
MPI_Reduce(&p.numTestCasesFailed, &g_numTestCasesFailed, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
|
||||
|
||||
std::vector<int> numAssertsFailedByRank;
|
||||
if(rank == 0){
|
||||
numAssertsFailedByRank.resize(static_cast<std::size_t>(n_rank));
|
||||
}
|
||||
|
||||
MPI_Gather(&p.numAssertsFailed, 1, MPI_INT, numAssertsFailedByRank.data(), 1, MPI_INT, 0, MPI_COMM_WORLD);
|
||||
|
||||
if(rank == 0) {
|
||||
separator_to_stream();
|
||||
s << Color::Cyan << "[doctest] " << Color::None << "assertions on all processes: " << std::setw(6)
|
||||
<< g_numAsserts << " | "
|
||||
<< ((g_numAsserts == 0 || anythingFailed) ? Color::None : Color::Green)
|
||||
<< std::setw(6) << (g_numAsserts - g_numAssertsFailed) << " passed" << Color::None
|
||||
<< " | " << (g_numAssertsFailed > 0 ? Color::Red : Color::None) << std::setw(6)
|
||||
<< g_numAssertsFailed << " failed" << Color::None << " |\n";
|
||||
if (nb_test_cases_skipped_insufficient_procs>0) {
|
||||
s << Color::Cyan << "[doctest] " << Color::Yellow << "WARNING: Skipped ";
|
||||
if (nb_test_cases_skipped_insufficient_procs>1) {
|
||||
s << nb_test_cases_skipped_insufficient_procs << " tests requiring more than ";
|
||||
} else {
|
||||
s << nb_test_cases_skipped_insufficient_procs << " test requiring more than ";
|
||||
}
|
||||
if (mpi_comm_world_size()>1) {
|
||||
s << mpi_comm_world_size() << " MPI processes to run\n";
|
||||
} else {
|
||||
s << mpi_comm_world_size() << " MPI process to run\n";
|
||||
}
|
||||
}
|
||||
|
||||
separator_to_stream();
|
||||
if(g_numAssertsFailed > 0){
|
||||
|
||||
s << Color::Cyan << "[doctest] " << Color::None << "fail on rank:" << std::setw(6) << "\n";
|
||||
for(std::size_t i = 0; i < numAssertsFailedByRank.size(); ++i){
|
||||
if( numAssertsFailedByRank[i] > 0 ){
|
||||
s << std::setw(16) << " -> On rank [" << i << "] with " << numAssertsFailedByRank[i] << " test failed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
s << Color::Cyan << "[doctest] " << Color::None
|
||||
<< "Status: " << (g_numTestCasesFailed > 0 ? Color::Red : Color::Green)
|
||||
<< ((g_numTestCasesFailed > 0) ? "FAILURE!" : "SUCCESS!") << Color::None << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void test_case_end(const CurrentTestCaseStats& st) override {
|
||||
if (is_mpi_test_case()) {
|
||||
// function called by every rank at the end of a test
|
||||
// if failed assertions happened, they have been sent to rank 0
|
||||
// here rank zero gathers them and prints them all
|
||||
|
||||
int rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
|
||||
std::vector<MPI_Request> requests;
|
||||
requests.reserve(m_failure_str_queue.size()); // avoid realloc & copy of MPI_Request
|
||||
for (const std::pair<std::string, int> &failure : m_failure_str_queue)
|
||||
{
|
||||
const std::string & failure_str = failure.first;
|
||||
const int failure_line = failure.second;
|
||||
|
||||
int failure_msg_size = static_cast<int>(failure_str.size());
|
||||
|
||||
requests.push_back(MPI_REQUEST_NULL);
|
||||
MPI_Isend(failure_str.c_str(), failure_msg_size, MPI_BYTE,
|
||||
0, failure_line, MPI_COMM_WORLD, &requests.back()); // Tag = file line
|
||||
}
|
||||
|
||||
|
||||
// Compute the number of assert with fail among all procs
|
||||
const int nb_fail_asserts = static_cast<int>(m_failure_str_queue.size());
|
||||
int nb_fail_asserts_glob = 0;
|
||||
MPI_Reduce(&nb_fail_asserts, &nb_fail_asserts_glob, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD);
|
||||
|
||||
if(rank == 0) {
|
||||
MPI_Status status;
|
||||
MPI_Status status_recv;
|
||||
|
||||
using id_string = std::pair<int,std::string>;
|
||||
std::vector<id_string> msgs(static_cast<std::size_t>(nb_fail_asserts_glob));
|
||||
|
||||
for (std::size_t i=0; i<static_cast<std::size_t>(nb_fail_asserts_glob); ++i) {
|
||||
MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
|
||||
|
||||
int count;
|
||||
MPI_Get_count(&status, MPI_BYTE, &count);
|
||||
|
||||
std::string recv_msg(static_cast<std::size_t>(count),'\0');
|
||||
void* recv_msg_data = const_cast<char*>(recv_msg.data()); // const_cast needed. Non-const .data() exists in C++11 though...
|
||||
MPI_Recv(recv_msg_data, count, MPI_BYTE, status.MPI_SOURCE,
|
||||
status.MPI_TAG, MPI_COMM_WORLD, &status_recv);
|
||||
|
||||
msgs[i] = {status.MPI_SOURCE,recv_msg};
|
||||
}
|
||||
|
||||
std::sort(begin(msgs),end(msgs),[](const id_string& x, const id_string& y){ return x.first < y.first; });
|
||||
|
||||
// print
|
||||
if (nb_fail_asserts_glob>0) {
|
||||
separator_to_stream();
|
||||
file_line_to_stream(tc->m_file.c_str(), static_cast<int>(tc->m_line), "\n");
|
||||
if(tc->m_test_suite && tc->m_test_suite[0] != '\0')
|
||||
s << Color::Yellow << "TEST SUITE: " << Color::None << tc->m_test_suite << "\n";
|
||||
if(strncmp(tc->m_name, " Scenario:", 11) != 0)
|
||||
s << Color::Yellow << "TEST CASE: ";
|
||||
s << Color::None << tc->m_name << "\n\n";
|
||||
for(const auto& msg : msgs) {
|
||||
s << msg.second;
|
||||
}
|
||||
s << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Waitall(static_cast<int>(requests.size()), requests.data(), MPI_STATUSES_IGNORE);
|
||||
m_failure_str_queue.clear();
|
||||
}
|
||||
|
||||
ConsoleReporter::test_case_end(st);
|
||||
}
|
||||
|
||||
bool is_mpi_test_case() const {
|
||||
return tc->m_description != nullptr
|
||||
&& std::string(tc->m_description) == std::string("MPI_TEST_CASE");
|
||||
}
|
||||
|
||||
void log_assert(const AssertData& rb) override {
|
||||
if (!is_mpi_test_case()) {
|
||||
ConsoleReporter::log_assert(rb);
|
||||
} else {
|
||||
int rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
|
||||
|
||||
|
||||
if(!rb.m_failed && !opt.success)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
|
||||
std::stringstream failure_msg;
|
||||
failure_msg << Color::Red << "On rank [" << rank << "] : " << Color::None;
|
||||
failure_msg << file_line_to_string(rb.m_file, rb.m_line, " ");
|
||||
|
||||
if((rb.m_at & (assertType::is_throws_as | assertType::is_throws_with)) ==0){
|
||||
failure_msg << Color::Cyan
|
||||
<< assertString(rb.m_at)
|
||||
<< "( " << rb.m_expr << " ) "
|
||||
<< Color::None
|
||||
|
||||
<< (!rb.m_failed ? "is correct!\n" : "is NOT correct!\n")
|
||||
<< " values: "
|
||||
<< assertString(rb.m_at)
|
||||
<< "( " << rb.m_decomp.c_str() << " )\n";
|
||||
}
|
||||
|
||||
m_failure_str_queue.push_back({failure_msg.str(), rb.m_line});
|
||||
}
|
||||
}
|
||||
}; // MpiConsoleReporter
|
||||
|
||||
// "1" is the priority - used for ordering when multiple reporters/listeners are used
|
||||
REGISTER_REPORTER("MpiConsoleReporter", 1, MpiConsoleReporter);
|
||||
REGISTER_REPORTER("MpiFileReporter", 1, MpiFileReporter);
|
||||
|
||||
} // anonymous
|
||||
} // doctest
|
||||
|
||||
#endif // DOCTEST_REPORTER_H
|
||||
84
include/doctest/extensions/mpi_sub_comm.h
Normal file
84
include/doctest/extensions/mpi_sub_comm.h
Normal file
@ -0,0 +1,84 @@
|
||||
#ifndef DOCTEST_MPI_SUB_COMM_H
|
||||
#define DOCTEST_MPI_SUB_COMM_H
|
||||
|
||||
#include "mpi.h"
|
||||
#include "doctest/doctest.h"
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
|
||||
namespace doctest {
|
||||
|
||||
inline
|
||||
int mpi_world_nb_procs() {
|
||||
int n;
|
||||
MPI_Comm_size(MPI_COMM_WORLD, &n);
|
||||
return n;
|
||||
}
|
||||
|
||||
struct mpi_sub_comm {
|
||||
int nb_procs;
|
||||
int rank;
|
||||
MPI_Comm comm;
|
||||
|
||||
mpi_sub_comm( mpi_sub_comm const& ) = delete;
|
||||
mpi_sub_comm& operator=( mpi_sub_comm const& ) = delete;
|
||||
|
||||
mpi_sub_comm(int nb_prcs) noexcept
|
||||
: nb_procs(nb_prcs)
|
||||
, rank(-1)
|
||||
, comm(MPI_COMM_NULL)
|
||||
{
|
||||
int comm_world_rank;
|
||||
MPI_Comm_rank(MPI_COMM_WORLD, &comm_world_rank);
|
||||
if (nb_procs>mpi_world_nb_procs()) {
|
||||
if (comm_world_rank==0) {
|
||||
MESSAGE(
|
||||
"Unable to run test: need ", std::to_string(nb_procs), " procs",
|
||||
" but program launched with only ", std::to_string(doctest::mpi_world_nb_procs()), "."
|
||||
);
|
||||
CHECK(nb_procs<=mpi_world_nb_procs());
|
||||
}
|
||||
} else {
|
||||
int color = MPI_UNDEFINED;
|
||||
if(comm_world_rank < nb_procs){
|
||||
color = 0;
|
||||
}
|
||||
MPI_Comm_split(MPI_COMM_WORLD, color, comm_world_rank, &comm);
|
||||
|
||||
if(comm != MPI_COMM_NULL){
|
||||
MPI_Comm_rank(comm, &rank);
|
||||
assert(rank==comm_world_rank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_comm() {
|
||||
if(comm != MPI_COMM_NULL){
|
||||
MPI_Comm_free(&comm);
|
||||
}
|
||||
}
|
||||
|
||||
mpi_sub_comm(mpi_sub_comm&& x)
|
||||
: nb_procs(x.nb_procs)
|
||||
, rank(x.rank)
|
||||
, comm(x.comm)
|
||||
{
|
||||
x.comm = MPI_COMM_NULL;
|
||||
}
|
||||
mpi_sub_comm& operator=(mpi_sub_comm&& x) {
|
||||
destroy_comm();
|
||||
nb_procs = x.nb_procs;
|
||||
rank = x.rank;
|
||||
comm = x.comm;
|
||||
x.comm = MPI_COMM_NULL;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~mpi_sub_comm() {
|
||||
destroy_comm();
|
||||
}
|
||||
};
|
||||
|
||||
} // doctest
|
||||
|
||||
#endif // DOCTEST_SUB_COMM_H
|
||||
295
include/highfive/H5Attribute.hpp
Normal file
295
include/highfive/H5Attribute.hpp
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Ali Can Demiralp <ali.demiralp@rwth-aachen.de>
|
||||
*
|
||||
* 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 <vector>
|
||||
|
||||
#include <H5Apublic.h>
|
||||
|
||||
#include "H5DataType.hpp"
|
||||
#include "H5DataSpace.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<class Derived>
|
||||
/// friend class SomeCRTP<Derived>;
|
||||
///
|
||||
/// \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<Attribute> {
|
||||
public:
|
||||
const static ObjectType type = ObjectType::Attribute;
|
||||
|
||||
/// \brief Get the name of the current Attribute.
|
||||
/// \code{.cpp}
|
||||
/// auto attr = dset.createAttribute<std::string>("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<int>("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<int>("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 a copy of the DataSpace of the current Attribute.
|
||||
/// \code{.cpp}
|
||||
/// Attribute attr = dset.createAttribute<int>("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 memory DataSpace of the current Attribute.
|
||||
///
|
||||
/// HDF5 attributes don't support selections. Therefore, there's no need
|
||||
/// for a memory dataspace. However, HighFive supports allocating arrays
|
||||
/// and checking dimensions, this requires the dimensions of the memspace.
|
||||
///
|
||||
/// \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<int> value = attr.read<std::vector<int>>();
|
||||
/// \endcode
|
||||
/// \since 2.5.0
|
||||
template <typename T>
|
||||
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<int> value(3);
|
||||
/// file.getAttribute("foo").read(value);
|
||||
/// \endcode
|
||||
/// \since 1.0
|
||||
template <typename T>
|
||||
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 <typename T>
|
||||
void read_raw(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 <typename T>
|
||||
void read_raw(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<int>{1, 2, 3});
|
||||
///
|
||||
/// // To overwrite the value:
|
||||
/// std::vector<int> value{4, 5, 6};
|
||||
/// dset.getAttribute<int>("foo").write(value);
|
||||
/// \endcode
|
||||
/// \since 1.0
|
||||
template <typename T>
|
||||
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<int>("foo", DataSpace(2, 3));
|
||||
///
|
||||
/// // Simulate the application creating `value` and only exposing access
|
||||
/// // to the raw pointer `ptr`.
|
||||
/// std::vector<std::array<int, 3>> value{{1, 2, 3}, {4, 5, 6}};
|
||||
/// int * ptr = (int*) value.data();
|
||||
///
|
||||
/// // Simply write the bytes to disk.
|
||||
/// attr.write(ptr, AtomicType<int>());
|
||||
/// \endcode
|
||||
/// \since 2.2.2
|
||||
template <typename T>
|
||||
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<std::array<int, 3>> 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 <typename T>
|
||||
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<AttributeCreateProps>(*this, H5Aget_create_plist);
|
||||
}
|
||||
|
||||
// No empty attributes
|
||||
Attribute() = delete;
|
||||
|
||||
///
|
||||
/// \brief Return an `Attribute` with `axes` squeezed from the memspace.
|
||||
///
|
||||
/// Returns an `Attribute` in which the memspace has been modified
|
||||
/// to not include the axes listed in `axes`.
|
||||
///
|
||||
/// Throws if any axis to be squeezes has a dimension other than `1`.
|
||||
///
|
||||
/// \since 3.0
|
||||
Attribute squeezeMemSpace(const std::vector<size_t>& axes) const;
|
||||
|
||||
///
|
||||
/// \brief Return a `Attribute` with a simple memspace with `dims`.
|
||||
///
|
||||
/// Returns a `Attribute` in which the memspace has been modified
|
||||
/// to be a simple dataspace with dimensions `dims`.
|
||||
///
|
||||
/// Throws if the number of elements changes.
|
||||
///
|
||||
/// \since 3.0
|
||||
Attribute reshapeMemSpace(const std::vector<size_t>& dims) const;
|
||||
|
||||
protected:
|
||||
using Object::Object;
|
||||
|
||||
private:
|
||||
DataSpace _mem_space;
|
||||
|
||||
#if HIGHFIVE_HAS_FRIEND_DECLARATIONS
|
||||
template <typename Derivate>
|
||||
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
|
||||
114
include/highfive/H5DataSet.hpp
Normal file
114
include/highfive/H5DataSet.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <vector>
|
||||
|
||||
#include "H5DataSpace.hpp"
|
||||
#include "H5DataType.hpp"
|
||||
#include "H5Object.hpp"
|
||||
#include "bits/H5_definitions.hpp"
|
||||
#include "bits/H5Annotate_traits.hpp"
|
||||
#include "bits/H5Slice_traits.hpp"
|
||||
#include "bits/H5Path_traits.hpp"
|
||||
#include "bits/H5_definitions.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
///
|
||||
/// \brief Class representing a dataset.
|
||||
///
|
||||
class DataSet: public Object,
|
||||
public SliceTraits<DataSet>,
|
||||
public AnnotateTraits<DataSet>,
|
||||
public PathTraits<DataSet> {
|
||||
public:
|
||||
const static ObjectType type = ObjectType::Dataset;
|
||||
|
||||
///
|
||||
/// \brief getStorageSize
|
||||
/// \return returns the amount of storage allocated for a dataset.
|
||||
///
|
||||
uint64_t getStorageSize() const;
|
||||
|
||||
///
|
||||
/// \brief getOffset
|
||||
/// \return returns DataSet address in file
|
||||
///
|
||||
uint64_t getOffset() 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 Change the size of the dataset
|
||||
///
|
||||
/// This requires that the dataset was created with chunking, and you would
|
||||
/// generally want to have set a larger maxdims setting
|
||||
/// \param dims New size of the dataset
|
||||
void resize(const std::vector<size_t>& dims);
|
||||
|
||||
|
||||
/// \brief Get the dimensions of the whole DataSet.
|
||||
/// This is a shorthand for getSpace().getDimensions()
|
||||
/// \return The shape of the current HighFive::DataSet
|
||||
///
|
||||
inline std::vector<size_t> getDimensions() const {
|
||||
return getSpace().getDimensions();
|
||||
}
|
||||
|
||||
/// \brief Get the total number of elements in the current dataset.
|
||||
/// E.g. 2x2x2 matrix has size 8.
|
||||
/// This is a shorthand for getSpace().getTotalCount()
|
||||
/// \return The shape of the current HighFive::DataSet
|
||||
///
|
||||
inline size_t getElementCount() const {
|
||||
return getSpace().getElementCount();
|
||||
}
|
||||
|
||||
/// \brief Get the list of properties for creation of this dataset
|
||||
DataSetCreateProps getCreatePropertyList() const {
|
||||
return details::get_plist<DataSetCreateProps>(*this, H5Dget_create_plist);
|
||||
}
|
||||
|
||||
/// \brief Get the list of properties for accession of this dataset
|
||||
DataSetAccessProps getAccessPropertyList() const {
|
||||
return details::get_plist<DataSetAccessProps>(*this, H5Dget_access_plist);
|
||||
}
|
||||
|
||||
DataSet() = default;
|
||||
|
||||
protected:
|
||||
using Object::Object; // bring DataSet(hid_t)
|
||||
|
||||
explicit DataSet(Object&& o) noexcept
|
||||
: Object(std::move(o)) {}
|
||||
|
||||
friend class Reference;
|
||||
template <typename Derivate>
|
||||
friend class NodeTraits;
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
282
include/highfive/H5DataSpace.hpp
Normal file
282
include/highfive/H5DataSpace.hpp
Normal file
@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <vector>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <initializer_list>
|
||||
|
||||
#include "H5Object.hpp"
|
||||
#include "bits/H5_definitions.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace detail {
|
||||
/// @brief Create a HighFive::DataSpace from an HID, without incrementing the id.
|
||||
///
|
||||
/// @note This is internal API and subject to change.
|
||||
/// @internal
|
||||
DataSpace make_data_space(hid_t hid);
|
||||
} // namespace detail
|
||||
|
||||
/// \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<size_t> 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<size_t>& dims, const
|
||||
/// std::vector<size_t>& 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 class DataspaceType {
|
||||
dataspace_scalar, ///< Value to create scalar DataSpace
|
||||
dataspace_null, ///< Value to create null DataSpace
|
||||
// simple dataspace are handle directly from their dimensions
|
||||
};
|
||||
|
||||
// For backward compatibility: `DataSpace::dataspace_scalar`.
|
||||
constexpr static DataspaceType dataspace_scalar = DataspaceType::dataspace_scalar;
|
||||
constexpr static DataspaceType dataspace_null = DataspaceType::dataspace_null;
|
||||
|
||||
/// \brief Create a DataSpace of N-dimensions from a std::vector<size_t>.
|
||||
/// \param dims Dimensions of the new DataSpace
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// // Create a DataSpace with 2 dimensions: 1 and 3
|
||||
/// DataSpace(std::vector<size_t>{1, 3});
|
||||
/// \endcode
|
||||
/// \since 1.0
|
||||
explicit DataSpace(const std::vector<size_t>& dims);
|
||||
|
||||
/// \brief Create a DataSpace of N-dimensions from a std::array<size_t, N>.
|
||||
/// \param dims Dimensions of the new DataSpace
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// // Create a DataSpace with 2 dimensions: 1 and 3
|
||||
/// DataSpace(std::array<size_t, 2>{1, 3});
|
||||
/// \endcode
|
||||
/// \since 2.3
|
||||
template <size_t N>
|
||||
explicit DataSpace(const std::array<size_t, N>& 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<size_t>& 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 <typename... Args>
|
||||
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<int> 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 <typename IT,
|
||||
typename = typename std::enable_if<!std::is_integral<IT>::value, IT>::type>
|
||||
DataSpace(IT begin, 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<size_t>{1, 3}, std::vector<size_t>{10, 10});
|
||||
/// \endcode
|
||||
///
|
||||
/// \see UNLIMITED for a DataSpace that can be resized without limit.
|
||||
/// \since 2.0
|
||||
explicit DataSpace(const std::vector<size_t>& dims, const std::vector<size_t>& 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 scalar DataSpace.
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// auto dataspace = DataSpace::Scalar();
|
||||
/// \endcode
|
||||
///
|
||||
/// \since 2.9
|
||||
static DataSpace Scalar();
|
||||
|
||||
/// \brief Create a null DataSpace.
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// auto dataspace = DataSpace::Null();
|
||||
/// \endcode
|
||||
///
|
||||
/// \since 2.9
|
||||
static DataSpace Null();
|
||||
|
||||
/// \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<size_t> 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<size_t>{1, 3}, std::vector<size_t>{UNLIMITED, 10});
|
||||
/// dspace.getMaxDimensions(); // Return {UNLIMITED, 10}
|
||||
/// \endcode
|
||||
///
|
||||
/// \sa DataSpace::getDimensions
|
||||
/// \since 2.0
|
||||
std::vector<size_t> 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<std::vector<int>> 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 <typename T>
|
||||
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 <std::size_t N, std::size_t Width>
|
||||
static DataSpace FromCharArrayStrings(const char (&string_array)[N][Width]);
|
||||
|
||||
protected:
|
||||
DataSpace() = default;
|
||||
|
||||
static DataSpace fromId(hid_t hid) {
|
||||
DataSpace space;
|
||||
space._hid = hid;
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
friend class Attribute;
|
||||
friend class File;
|
||||
friend class DataSet;
|
||||
|
||||
friend DataSpace detail::make_data_space(hid_t hid);
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
|
||||
// We include bits right away since DataSpace is user-constructible
|
||||
#include "bits/H5Dataspace_misc.hpp"
|
||||
367
include/highfive/H5DataType.hpp
Normal file
367
include/highfive/H5DataType.hpp
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <H5Tpublic.h>
|
||||
|
||||
#include "H5Object.hpp"
|
||||
#include "bits/H5Utils.hpp"
|
||||
|
||||
#include "bits/string_padding.hpp"
|
||||
#include "H5PropertyList.hpp"
|
||||
|
||||
#include "bits/h5_wrapper.hpp"
|
||||
#include "bits/h5t_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
|
||||
///
|
||||
/// \brief Enum of Fundamental data classes
|
||||
///
|
||||
enum class DataTypeClass {
|
||||
Time = 1 << 1,
|
||||
Integer = 1 << 2,
|
||||
Float = 1 << 3,
|
||||
String = 1 << 4,
|
||||
BitField = 1 << 5,
|
||||
Opaque = 1 << 6,
|
||||
Compound = 1 << 7,
|
||||
Reference = 1 << 8,
|
||||
Enum = 1 << 9,
|
||||
VarLen = 1 << 10,
|
||||
Array = 1 << 11,
|
||||
Invalid = 0
|
||||
};
|
||||
|
||||
inline DataTypeClass operator|(DataTypeClass lhs, DataTypeClass rhs) {
|
||||
using T = std::underlying_type<DataTypeClass>::type;
|
||||
return static_cast<DataTypeClass>(static_cast<T>(lhs) | static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
inline DataTypeClass operator&(DataTypeClass lhs, DataTypeClass rhs) {
|
||||
using T = std::underlying_type<DataTypeClass>::type;
|
||||
return static_cast<DataTypeClass>(static_cast<T>(lhs) & static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
class StringType;
|
||||
|
||||
///
|
||||
/// \brief HDF5 Data Type
|
||||
///
|
||||
class DataType: public Object {
|
||||
public:
|
||||
bool operator==(const DataType& other) const;
|
||||
|
||||
bool operator!=(const DataType& other) const;
|
||||
|
||||
///
|
||||
/// \brief Return the fundamental type.
|
||||
///
|
||||
DataTypeClass getClass() const;
|
||||
|
||||
///
|
||||
/// \brief Returns the length (in bytes) of this type elements
|
||||
///
|
||||
/// Notice that the size of variable length sequences may have limited applicability
|
||||
/// given that it refers to the size of the control structure. For info see
|
||||
/// https://support.hdfgroup.org/HDF5/doc/RM/RM_H5T.html#Datatype-GetSize
|
||||
size_t getSize() const;
|
||||
|
||||
///
|
||||
/// \brief Returns a friendly description of the type (e.g. Float32)
|
||||
///
|
||||
std::string string() const;
|
||||
|
||||
///
|
||||
/// \brief Returns whether the type is a variable-length string
|
||||
///
|
||||
bool isVariableStr() const;
|
||||
|
||||
///
|
||||
/// \brief Returns whether the type is a fixed-length string
|
||||
///
|
||||
bool isFixedLenStr() const;
|
||||
|
||||
///
|
||||
/// \brief Returns this datatype as a `StringType`.
|
||||
///
|
||||
StringType asStringType() const;
|
||||
|
||||
///
|
||||
/// \brief Check the DataType was default constructed.
|
||||
///
|
||||
bool empty() const noexcept;
|
||||
|
||||
/// \brief Returns whether the type is a Reference
|
||||
bool isReference() const;
|
||||
|
||||
/// \brief Get the list of properties for creation of this DataType
|
||||
DataTypeCreateProps getCreatePropertyList() const {
|
||||
return details::get_plist<DataTypeCreateProps>(*this, H5Tget_create_plist);
|
||||
}
|
||||
|
||||
protected:
|
||||
using Object::Object;
|
||||
|
||||
friend class Attribute;
|
||||
friend class File;
|
||||
friend class DataSet;
|
||||
friend class CompoundType;
|
||||
template <typename Derivate>
|
||||
friend class NodeTraits;
|
||||
};
|
||||
|
||||
|
||||
enum class CharacterSet : std::underlying_type<H5T_cset_t>::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. While
|
||||
/// commonly, a null-terminated string is guaranteed to have one `'\0'`
|
||||
/// which marks the semantic end of the string, this is not enforced by
|
||||
/// HDF5. In fact, there are HDF5 files that contain strings that claim to
|
||||
/// be null-terminated but aren't. The length of the buffer must be at
|
||||
/// least `size` bytes regardless of the padding. HDF5 will read or write
|
||||
/// `size` bytes, irrespective of when (if at all) 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 null-terminated. Otherwise prefer a
|
||||
/// null-padded string. This mearly 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.
|
||||
///
|
||||
explicit VariableLengthStringType(CharacterSet character_set = CharacterSet::Ascii);
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief create an HDF5 DataType from a C++ type
|
||||
///
|
||||
/// Support only basic data type
|
||||
///
|
||||
template <typename T>
|
||||
class AtomicType: public DataType {
|
||||
public:
|
||||
AtomicType();
|
||||
|
||||
using basic_type = T;
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief Create a compound HDF5 datatype
|
||||
///
|
||||
class CompoundType: public DataType {
|
||||
public:
|
||||
///
|
||||
/// \brief Use for defining a sub-type of compound type
|
||||
struct member_def {
|
||||
member_def(std::string t_name, DataType t_base_type, size_t t_offset = 0)
|
||||
: name(std::move(t_name))
|
||||
, base_type(std::move(t_base_type))
|
||||
, offset(t_offset) {}
|
||||
std::string name;
|
||||
DataType base_type;
|
||||
size_t offset;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Initializes a compound type from a vector of member definitions
|
||||
/// \param t_members
|
||||
/// \param size
|
||||
inline CompoundType(const std::vector<member_def>& t_members, size_t size = 0)
|
||||
: members(t_members) {
|
||||
create(size);
|
||||
}
|
||||
inline CompoundType(std::vector<member_def>&& t_members, size_t size = 0)
|
||||
: members(std::move(t_members)) {
|
||||
create(size);
|
||||
}
|
||||
inline CompoundType(const std::initializer_list<member_def>& t_members, size_t size = 0)
|
||||
: members(t_members) {
|
||||
create(size);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Initializes a compound type from a DataType
|
||||
/// \param type
|
||||
inline explicit CompoundType(DataType&& type)
|
||||
: DataType(type) {
|
||||
if (getClass() != DataTypeClass::Compound) {
|
||||
std::ostringstream ss;
|
||||
ss << "hid " << _hid << " does not refer to a compound data type";
|
||||
throw DataTypeException(ss.str());
|
||||
}
|
||||
size_t n_members = static_cast<size_t>(detail::h5t_get_nmembers(_hid));
|
||||
members.reserve(n_members);
|
||||
for (unsigned i = 0; i < n_members; i++) {
|
||||
char* name = detail::h5t_get_member_name(_hid, i);
|
||||
size_t offset = detail::h5t_get_member_offset(_hid, i);
|
||||
hid_t member_hid = detail::h5t_get_member_type(_hid, i);
|
||||
DataType member_type{member_hid};
|
||||
members.emplace_back(std::string(name), member_type, offset);
|
||||
|
||||
detail::h5_free_memory(name);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Commit datatype into the given Object
|
||||
/// \param object Location to commit object into
|
||||
/// \param name Name to give the datatype
|
||||
inline void commit(const Object& object, const std::string& name) const;
|
||||
|
||||
/// \brief Get read access to the CompoundType members
|
||||
inline const std::vector<member_def>& getMembers() const noexcept {
|
||||
return members;
|
||||
}
|
||||
|
||||
private:
|
||||
/// A vector of the member_def members of this CompoundType
|
||||
std::vector<member_def> members;
|
||||
|
||||
/// \brief Automatically create the type from the set of members
|
||||
/// using standard struct alignment.
|
||||
/// \param size Total size of data type
|
||||
void create(size_t size = 0);
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Create a enum HDF5 datatype
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// enum class Position {
|
||||
/// FIRST = 1,
|
||||
/// SECOND = 2,
|
||||
/// };
|
||||
///
|
||||
/// EnumType<Position> create_enum_position() {
|
||||
/// return {{"FIRST", Position::FIRST},
|
||||
/// {"SECOND", Position::SECOND}};
|
||||
/// }
|
||||
///
|
||||
/// // You have to register the type inside HighFive
|
||||
/// HIGHFIVE_REGISTER_TYPE(Position, create_enum_position)
|
||||
///
|
||||
/// void write_first(H5::File& file) {
|
||||
/// auto dataset = file.createDataSet("/foo", Position::FIRST);
|
||||
/// }
|
||||
/// \endcode
|
||||
template <typename T>
|
||||
class EnumType: public DataType {
|
||||
public:
|
||||
///
|
||||
/// \brief Use for defining a member of enum type
|
||||
struct member_def {
|
||||
member_def(const std::string& t_name, T t_value)
|
||||
: name(t_name)
|
||||
, value(std::move(t_value)) {}
|
||||
std::string name;
|
||||
T value;
|
||||
};
|
||||
|
||||
EnumType(const EnumType& other) = default;
|
||||
|
||||
EnumType(const std::vector<member_def>& t_members)
|
||||
: members(t_members) {
|
||||
static_assert(std::is_enum<T>::value, "EnumType<T>::create takes only enum");
|
||||
if (members.empty()) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
"Could not create an enum without members");
|
||||
}
|
||||
create();
|
||||
}
|
||||
|
||||
EnumType(std::initializer_list<member_def> t_members)
|
||||
: EnumType(std::vector<member_def>(t_members)) {}
|
||||
|
||||
/// \brief Commit datatype into the given Object
|
||||
/// \param object Location to commit object into
|
||||
/// \param name Name to give the datatype
|
||||
void commit(const Object& object, const std::string& name) const;
|
||||
|
||||
private:
|
||||
std::vector<member_def> members;
|
||||
|
||||
void create();
|
||||
};
|
||||
|
||||
|
||||
/// \brief Create a DataType instance representing type T
|
||||
template <typename T>
|
||||
DataType create_datatype();
|
||||
|
||||
|
||||
/// \brief Create a DataType instance representing type T and perform a sanity check on its size
|
||||
template <typename T>
|
||||
DataType create_and_check_datatype();
|
||||
} // namespace HighFive
|
||||
|
||||
|
||||
/// \brief Macro to extend datatype of HighFive
|
||||
///
|
||||
/// This macro has to be called outside of any namespace.
|
||||
///
|
||||
/// \code{.cpp}
|
||||
/// namespace app {
|
||||
/// enum FooBar { FOO = 1, BAR = 2 };
|
||||
/// EnumType create_enum_foobar() {
|
||||
/// return EnumType<FooBar>({{"FOO", FooBar::FOO},
|
||||
/// {"BAR", FooBar::BAR}});
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// HIGHFIVE_REGISTER_TYPE(FooBar, ::app::create_enum_foobar)
|
||||
/// \endcode
|
||||
#define HIGHFIVE_REGISTER_TYPE(type, function) \
|
||||
template <> \
|
||||
inline HighFive::DataType HighFive::create_datatype<type>() { \
|
||||
return function(); \
|
||||
}
|
||||
|
||||
#include "bits/H5DataType_misc.hpp"
|
||||
398
include/highfive/H5Easy.hpp
Normal file
398
include/highfive/H5Easy.hpp
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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)
|
||||
*
|
||||
*/
|
||||
|
||||
/// \brief
|
||||
/// Read/dump DataSets or Attribute using a minimalistic syntax.
|
||||
/// To this end, the functions are templated, and accept:
|
||||
/// - Any type accepted by HighFive
|
||||
/// - Eigen objects
|
||||
/// - xtensor objects
|
||||
/// - OpenCV objects
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// optionally enable xtensor plug-in and load the library
|
||||
#ifdef XTENSOR_VERSION_MAJOR
|
||||
#ifndef H5_USE_XTENSOR
|
||||
#define H5_USE_XTENSOR
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef H5_USE_XTENSOR
|
||||
#include "xtensor.hpp"
|
||||
#endif
|
||||
|
||||
// optionally enable Eigen plug-in and load the library
|
||||
#ifdef EIGEN_WORLD_VERSION
|
||||
#ifndef H5_USE_EIGEN
|
||||
#define H5_USE_EIGEN
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef H5_USE_EIGEN
|
||||
#include <Eigen/Eigen>
|
||||
#include "eigen.hpp"
|
||||
#endif
|
||||
|
||||
// optionally enable OpenCV plug-in and load the library
|
||||
#ifdef CV_MAJOR_VERSION
|
||||
#ifndef H5_USE_OPENCV
|
||||
#define H5_USE_OPENCV
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef H5_USE_OPENCV
|
||||
#include <opencv2/opencv.hpp>
|
||||
#include "experimental/opencv.hpp"
|
||||
#endif
|
||||
|
||||
#include "H5File.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
|
||||
using HighFive::AtomicType;
|
||||
using HighFive::Attribute;
|
||||
using HighFive::Chunking;
|
||||
using HighFive::DataSet;
|
||||
using HighFive::DataSetCreateProps;
|
||||
using HighFive::DataSpace;
|
||||
using HighFive::Deflate;
|
||||
using HighFive::Exception;
|
||||
using HighFive::File;
|
||||
using HighFive::ObjectType;
|
||||
using HighFive::Shuffle;
|
||||
|
||||
///
|
||||
/// \brief Write mode for DataSets
|
||||
enum class DumpMode {
|
||||
Create = 0, /*!< Dump only if DataSet does not exist, otherwise throw. */
|
||||
Overwrite = 1 /*!< Create or overwrite if DataSet of correct shape exists, otherwise throw. */
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Signal to enable/disable automatic flushing after write operations.
|
||||
enum class Flush {
|
||||
False = 0, /*!< No automatic flushing. */
|
||||
True = 1 /*!< Automatic flushing. */
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Signal to set compression level for written DataSets.
|
||||
class Compression {
|
||||
public:
|
||||
///
|
||||
/// \brief Enable compression with the highest compression level (9).
|
||||
/// or disable compression (set compression level to 0).
|
||||
///
|
||||
/// \param enable ``true`` to enable with highest compression level
|
||||
explicit Compression(bool enable = true);
|
||||
|
||||
///
|
||||
/// \brief Set compression level.
|
||||
///
|
||||
/// \param level the compression level
|
||||
template <class T>
|
||||
Compression(T level);
|
||||
|
||||
///
|
||||
/// \brief Return compression level.
|
||||
inline unsigned get() const;
|
||||
|
||||
private:
|
||||
unsigned m_compression_level;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Define options for dumping data.
|
||||
///
|
||||
/// By default:
|
||||
/// - DumpMode::Create
|
||||
/// - Flush::True
|
||||
/// - Compression: false
|
||||
/// - ChunkSize: automatic
|
||||
class DumpOptions {
|
||||
public:
|
||||
///
|
||||
/// \brief Constructor: accept all default settings.
|
||||
DumpOptions() = default;
|
||||
|
||||
///
|
||||
/// \brief Constructor: overwrite (some of the) defaults.
|
||||
/// \param args any of DumpMode(), Flush(), Compression() in arbitrary number and order.
|
||||
template <class... Args>
|
||||
DumpOptions(Args... args) {
|
||||
set(args...);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Overwrite H5Easy::DumpMode setting.
|
||||
/// \param mode: DumpMode.
|
||||
inline void set(DumpMode mode);
|
||||
|
||||
///
|
||||
/// \brief Overwrite H5Easy::Flush setting.
|
||||
/// \param mode Flush.
|
||||
inline void set(Flush mode);
|
||||
|
||||
///
|
||||
/// \brief Overwrite H5Easy::Compression setting.
|
||||
/// \param level Compression.
|
||||
inline void set(const Compression& level);
|
||||
|
||||
///
|
||||
/// \brief Overwrite any setting(s).
|
||||
/// \param arg any of DumpMode(), Flush(), Compression in arbitrary number and order.
|
||||
/// \param args any of DumpMode(), Flush(), Compression in arbitrary number and order.
|
||||
template <class T, class... Args>
|
||||
inline void set(T arg, Args... args);
|
||||
|
||||
///
|
||||
/// \brief Set chunk-size. If the input is rank (size) zero, automatic chunking is enabled.
|
||||
/// \param shape Chunk size along each dimension.
|
||||
template <class T>
|
||||
inline void setChunkSize(const std::vector<T>& shape);
|
||||
|
||||
///
|
||||
/// \brief Set chunk-size. If the input is rank (size) zero, automatic chunking is enabled.
|
||||
/// \param shape Chunk size along each dimension.
|
||||
inline void setChunkSize(std::initializer_list<size_t> shape);
|
||||
|
||||
///
|
||||
/// \brief Get overwrite-mode.
|
||||
/// \return bool
|
||||
inline bool overwrite() const;
|
||||
|
||||
///
|
||||
/// \brief Get flush-mode.
|
||||
/// \return bool
|
||||
inline bool flush() const;
|
||||
|
||||
///
|
||||
/// \brief Get compress-mode.
|
||||
/// \return bool
|
||||
inline bool compress() const;
|
||||
|
||||
///
|
||||
/// \brief Get compression level.
|
||||
/// \return [0..9]
|
||||
inline unsigned getCompressionLevel() const;
|
||||
|
||||
///
|
||||
/// \brief Get chunking mode: ``true`` is manually set, ``false`` if chunk-size should be
|
||||
/// computed automatically.
|
||||
/// \return bool
|
||||
inline bool isChunked() const;
|
||||
|
||||
///
|
||||
/// \brief Get chunk size. Use DumpOptions::getChunkSize to check if chunk-size should
|
||||
/// be automatically computed.
|
||||
inline std::vector<hsize_t> getChunkSize() const;
|
||||
|
||||
private:
|
||||
bool m_overwrite = false;
|
||||
bool m_flush = true;
|
||||
unsigned m_compression_level = 0;
|
||||
std::vector<hsize_t> m_chunk_size = {};
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Get the size of an existing DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be readable)
|
||||
/// \param path path of the DataSet
|
||||
///
|
||||
/// \return Size of the DataSet
|
||||
inline size_t getSize(const File& file, const std::string& path);
|
||||
|
||||
///
|
||||
/// \brief Get the shape of an existing DataSet in an readable file.
|
||||
///
|
||||
/// \param file opened file (has to be readable)
|
||||
/// \param path Path of the DataSet
|
||||
///
|
||||
/// \return the shape of the DataSet
|
||||
inline std::vector<size_t> getShape(const File& file, const std::string& path);
|
||||
|
||||
///
|
||||
/// \brief Write object (templated) to a (new) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param mode write mode
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
DumpMode mode = DumpMode::Create);
|
||||
|
||||
///
|
||||
/// \brief Write object (templated) to a (new) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param options dump options
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file, const std::string& path, const T& data, const DumpOptions& options);
|
||||
|
||||
///
|
||||
/// \brief Write a scalar to a (new, extendible) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param idx the indices to which to write
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::vector<size_t>& idx);
|
||||
|
||||
///
|
||||
/// \brief Write a scalar to a (new, extendable) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file open File (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param idx the indices to which to write
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::initializer_list<size_t>& idx);
|
||||
|
||||
///
|
||||
/// \brief Write a scalar to a (new, extendible) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param idx the indices to which to write
|
||||
/// \param options dump options
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::vector<size_t>& idx,
|
||||
const DumpOptions& options);
|
||||
|
||||
///
|
||||
/// \brief Write a scalar to a (new, extendible) DataSet in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param idx the indices to which to write
|
||||
/// \param options dump options
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::initializer_list<size_t>& idx,
|
||||
const DumpOptions& options);
|
||||
|
||||
///
|
||||
/// \brief Load entry ``{i, j, ...}`` from a DataSet in an open HDF5 file to a scalar.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param idx the indices to load
|
||||
/// \param path path of the DataSet
|
||||
///
|
||||
/// \return The read data
|
||||
///
|
||||
template <class T>
|
||||
inline T load(const File& file, const std::string& path, const std::vector<size_t>& idx);
|
||||
|
||||
///
|
||||
/// \brief Load a DataSet in an open HDF5 file to an object (templated).
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
///
|
||||
/// \return The read data
|
||||
///
|
||||
template <class T>
|
||||
inline T load(const File& file, const std::string& path);
|
||||
|
||||
///
|
||||
/// \brief Write object (templated) to a (new) Attribute in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param key name of the attribute
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param mode write mode
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
DumpMode mode = DumpMode::Create);
|
||||
|
||||
///
|
||||
/// \brief Write object (templated) to a (new) Attribute in an open HDF5 file.
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param key name of the attribute
|
||||
/// \param data the data to write (any supported type)
|
||||
/// \param options dump options
|
||||
///
|
||||
/// \return The newly created DataSet
|
||||
///
|
||||
template <class T>
|
||||
inline Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
const DumpOptions& options);
|
||||
|
||||
///
|
||||
/// \brief Load a Attribute in an open HDF5 file to an object (templated).
|
||||
///
|
||||
/// \param file opened file (has to be writeable)
|
||||
/// \param path path of the DataSet
|
||||
/// \param key name of the attribute
|
||||
///
|
||||
/// \return The read data
|
||||
///
|
||||
template <class T>
|
||||
inline T loadAttribute(const File& file, const std::string& path, const std::string& key);
|
||||
|
||||
} // namespace H5Easy
|
||||
|
||||
#include "h5easy_bits/H5Easy_Eigen.hpp"
|
||||
#include "h5easy_bits/H5Easy_misc.hpp"
|
||||
#include "h5easy_bits/H5Easy_public.hpp"
|
||||
#include "h5easy_bits/H5Easy_scalar.hpp"
|
||||
167
include/highfive/H5Exception.hpp
Normal file
167
include/highfive/H5Exception.hpp
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
///
|
||||
/// \brief Basic HighFive Exception class
|
||||
///
|
||||
///
|
||||
class Exception: public std::exception {
|
||||
public:
|
||||
explicit Exception(const std::string& err_msg)
|
||||
: _errmsg(err_msg) {}
|
||||
|
||||
Exception(const Exception& other) = default;
|
||||
Exception(Exception&& other) noexcept = default;
|
||||
|
||||
Exception& operator=(const Exception& other) = default;
|
||||
Exception& operator=(Exception&& other) noexcept = default;
|
||||
|
||||
~Exception() noexcept override {}
|
||||
|
||||
///
|
||||
/// \brief get the current exception error message
|
||||
/// \return
|
||||
///
|
||||
inline const char* what() const noexcept override {
|
||||
return _errmsg.c_str();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief define the error message
|
||||
/// \param errmsg
|
||||
///
|
||||
inline virtual void setErrorMsg(const std::string& errmsg) {
|
||||
_errmsg = errmsg;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief nextException
|
||||
/// \return pointer to the next exception in the chain, or NULL if not
|
||||
/// existing
|
||||
///
|
||||
inline Exception* nextException() const {
|
||||
return _next.get();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief HDF5 library error mapper
|
||||
/// \return HDF5 major error number
|
||||
///
|
||||
inline hid_t getErrMajor() const {
|
||||
return _err_major;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief HDF5 library error mapper
|
||||
/// \return HDF5 minor error number
|
||||
///
|
||||
inline hid_t getErrMinor() const {
|
||||
return _err_minor;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _errmsg;
|
||||
std::shared_ptr<Exception> _next = nullptr;
|
||||
hid_t _err_major = 0, _err_minor = 0;
|
||||
|
||||
friend struct HDF5ErrMapper;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive Object interface
|
||||
///
|
||||
class ObjectException: public Exception {
|
||||
public:
|
||||
explicit ObjectException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive DataType interface
|
||||
///
|
||||
class DataTypeException: public Exception {
|
||||
public:
|
||||
explicit DataTypeException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive File interface
|
||||
///
|
||||
class FileException: public Exception {
|
||||
public:
|
||||
explicit FileException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive DataSpace interface
|
||||
///
|
||||
class DataSpaceException: public Exception {
|
||||
public:
|
||||
explicit DataSpaceException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive Attribute interface
|
||||
///
|
||||
class AttributeException: public Exception {
|
||||
public:
|
||||
explicit AttributeException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive DataSet interface
|
||||
///
|
||||
class DataSetException: public Exception {
|
||||
public:
|
||||
explicit DataSetException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive Group interface
|
||||
///
|
||||
class GroupException: public Exception {
|
||||
public:
|
||||
explicit GroupException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive Property interface
|
||||
///
|
||||
class PropertyException: public Exception {
|
||||
public:
|
||||
explicit PropertyException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Exception specific to HighFive Reference interface
|
||||
///
|
||||
class ReferenceException: public Exception {
|
||||
public:
|
||||
explicit ReferenceException(const std::string& err_msg)
|
||||
: Exception(err_msg) {}
|
||||
};
|
||||
} // namespace HighFive
|
||||
|
||||
#include "bits/H5Exception_misc.hpp"
|
||||
203
include/highfive/H5File.hpp
Normal file
203
include/highfive/H5File.hpp
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "H5Object.hpp"
|
||||
#include "H5PropertyList.hpp"
|
||||
#include "bits/H5Annotate_traits.hpp"
|
||||
#include "bits/H5Node_traits.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
|
||||
///
|
||||
/// \brief File class
|
||||
///
|
||||
class File: public Object, public NodeTraits<File>, public AnnotateTraits<File> {
|
||||
public:
|
||||
const static ObjectType type = ObjectType::File;
|
||||
|
||||
enum class AccessMode {
|
||||
None = 0x00u,
|
||||
/// Open flag: Read only access
|
||||
ReadOnly = 0x01u,
|
||||
/// Open flag: Read Write access
|
||||
ReadWrite = 0x02u,
|
||||
/// Open flag: Truncate a file if already existing
|
||||
Truncate = 0x04u,
|
||||
/// Open flag: Open will fail if file already exist
|
||||
Excl = 0x08u,
|
||||
/// Open flag: Open in debug mode
|
||||
Debug = 0x10u,
|
||||
/// Open flag: Create non existing file
|
||||
Create = 0x20u,
|
||||
/// Derived open flag: common write mode (=ReadWrite|Create|Truncate)
|
||||
Overwrite = Truncate,
|
||||
/// Derived open flag: Opens RW or exclusively creates
|
||||
OpenOrCreate = ReadWrite | Create
|
||||
};
|
||||
|
||||
constexpr static AccessMode ReadOnly = AccessMode::ReadOnly;
|
||||
constexpr static AccessMode ReadWrite = AccessMode::ReadWrite;
|
||||
constexpr static AccessMode Truncate = AccessMode::Truncate;
|
||||
constexpr static AccessMode Excl = AccessMode::Excl;
|
||||
constexpr static AccessMode Debug = AccessMode::Debug;
|
||||
constexpr static AccessMode Create = AccessMode::Create;
|
||||
constexpr static AccessMode Overwrite = AccessMode::Overwrite;
|
||||
constexpr static AccessMode OpenOrCreate = AccessMode::OpenOrCreate;
|
||||
|
||||
///
|
||||
/// \brief File
|
||||
/// \param filename: filepath of the HDF5 file
|
||||
/// \param openFlags: Open mode / flags ( ReadOnly, ReadWrite)
|
||||
/// \param fileAccessProps: the file access properties
|
||||
///
|
||||
/// Open or create a new HDF5 file
|
||||
explicit File(const std::string& filename,
|
||||
AccessMode openFlags = ReadOnly,
|
||||
const FileAccessProps& fileAccessProps = FileAccessProps::Default());
|
||||
|
||||
///
|
||||
/// \brief File
|
||||
/// \param filename: filepath of the HDF5 file
|
||||
/// \param access_mode: Open mode / flags ( ReadOnly, ReadWrite, etc.)
|
||||
/// \param fileCreateProps: the file create properties
|
||||
/// \param fileAccessProps: the file access properties
|
||||
///
|
||||
/// Open or create a new HDF5 file
|
||||
File(const std::string& filename,
|
||||
AccessMode access_mode,
|
||||
const FileCreateProps& fileCreateProps,
|
||||
const FileAccessProps& fileAccessProps = FileAccessProps::Default());
|
||||
|
||||
/// \brief Keeps reference count constant, and invalidates other.
|
||||
File(File&& other) noexcept = default;
|
||||
|
||||
/// \brief Keeps reference count constant, and invalidates other.
|
||||
File& operator=(File&& other) = default;
|
||||
|
||||
/// \brief Increments reference count, keeps other valid.
|
||||
File(const File& other) = default;
|
||||
|
||||
/// \brief Increments reference count, keeps other valid.
|
||||
File& operator=(const File& other) = default;
|
||||
|
||||
///
|
||||
/// \brief Return the name of the file
|
||||
///
|
||||
const std::string& getName() const;
|
||||
|
||||
/// \brief Object path of a File is always "/"
|
||||
std::string getPath() const noexcept {
|
||||
return "/";
|
||||
}
|
||||
|
||||
/// \brief Returns the block size for metadata in bytes
|
||||
hsize_t getMetadataBlockSize() const;
|
||||
|
||||
/// \brief Returns the HDF5 version compatibility bounds
|
||||
std::pair<H5F_libver_t, H5F_libver_t> getVersionBounds() const;
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 1)
|
||||
/// \brief Returns the HDF5 file space strategy.
|
||||
H5F_fspace_strategy_t getFileSpaceStrategy() const;
|
||||
|
||||
/// \brief Returns the page size, if paged allocation is used.
|
||||
hsize_t getFileSpacePageSize() const;
|
||||
#endif
|
||||
|
||||
///
|
||||
/// \brief flush
|
||||
///
|
||||
/// Flushes all buffers associated with a file to disk
|
||||
///
|
||||
void flush();
|
||||
|
||||
/// \brief Get the list of properties for creation of this file
|
||||
FileCreateProps getCreatePropertyList() const {
|
||||
return details::get_plist<FileCreateProps>(*this, H5Fget_create_plist);
|
||||
}
|
||||
|
||||
/// \brief Get the list of properties for accession of this file
|
||||
FileAccessProps getAccessPropertyList() const {
|
||||
return details::get_plist<FileAccessProps>(*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;
|
||||
|
||||
private:
|
||||
mutable std::string _filename{};
|
||||
|
||||
template <typename>
|
||||
friend class PathTraits;
|
||||
};
|
||||
|
||||
inline File::AccessMode operator|(File::AccessMode lhs, File::AccessMode rhs) {
|
||||
using int_t = std::underlying_type<File::AccessMode>::type;
|
||||
return static_cast<File::AccessMode>(static_cast<int_t>(lhs) | static_cast<int_t>(rhs));
|
||||
}
|
||||
|
||||
inline File::AccessMode operator&(File::AccessMode lhs, File::AccessMode rhs) {
|
||||
using int_t = std::underlying_type<File::AccessMode>::type;
|
||||
return static_cast<File::AccessMode>(static_cast<int_t>(lhs) & static_cast<int_t>(rhs));
|
||||
}
|
||||
|
||||
inline File::AccessMode operator^(File::AccessMode lhs, File::AccessMode rhs) {
|
||||
using int_t = std::underlying_type<File::AccessMode>::type;
|
||||
return static_cast<File::AccessMode>(static_cast<int_t>(lhs) ^ static_cast<int_t>(rhs));
|
||||
}
|
||||
|
||||
inline File::AccessMode operator~(File::AccessMode mode) {
|
||||
using int_t = std::underlying_type<File::AccessMode>::type;
|
||||
return static_cast<File::AccessMode>(~static_cast<int_t>(mode));
|
||||
}
|
||||
|
||||
inline const File::AccessMode& operator|=(File::AccessMode& lhs, File::AccessMode rhs) {
|
||||
lhs = lhs | rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline File::AccessMode operator&=(File::AccessMode& lhs, File::AccessMode rhs) {
|
||||
lhs = lhs & rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline File::AccessMode operator^=(File::AccessMode& lhs, File::AccessMode rhs) {
|
||||
lhs = lhs ^ rhs;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
inline bool any(File::AccessMode mode) {
|
||||
return mode != File::AccessMode::None;
|
||||
}
|
||||
|
||||
|
||||
} // namespace HighFive
|
||||
|
||||
// H5File is the main user constructible -> bring in implementation headers
|
||||
#include "bits/H5Annotate_traits_misc.hpp"
|
||||
#include "bits/H5File_misc.hpp"
|
||||
#include "bits/H5Node_traits_misc.hpp"
|
||||
#include "bits/H5Path_traits_misc.hpp"
|
||||
86
include/highfive/H5Group.hpp
Normal file
86
include/highfive/H5Group.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <H5Gpublic.h>
|
||||
|
||||
#include "H5Object.hpp"
|
||||
#include "bits/H5Friends.hpp"
|
||||
#include "bits/H5_definitions.hpp"
|
||||
#include "bits/H5Annotate_traits.hpp"
|
||||
#include "bits/H5Node_traits.hpp"
|
||||
#include "bits/H5Path_traits.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace detail {
|
||||
/// \brief Internal hack to create an `Group` from an ID.
|
||||
///
|
||||
/// WARNING: Creating an Group 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<class Derived>
|
||||
/// friend class SomeCRTP<Derived>;
|
||||
///
|
||||
/// \private
|
||||
Group make_group(hid_t);
|
||||
} // namespace detail
|
||||
|
||||
///
|
||||
/// \brief Represents an hdf5 group
|
||||
class Group: public Object,
|
||||
public NodeTraits<Group>,
|
||||
public AnnotateTraits<Group>,
|
||||
public PathTraits<Group> {
|
||||
public:
|
||||
const static ObjectType type = ObjectType::Group;
|
||||
|
||||
Group() = default;
|
||||
|
||||
std::pair<unsigned int, unsigned int> getEstimatedLinkInfo() const;
|
||||
|
||||
/// \brief Get the list of properties for creation of this group
|
||||
GroupCreateProps getCreatePropertyList() const {
|
||||
return details::get_plist<GroupCreateProps>(*this, H5Gget_create_plist);
|
||||
}
|
||||
|
||||
explicit Group(Object&& o) noexcept
|
||||
: Object(std::move(o)) {};
|
||||
|
||||
protected:
|
||||
using Object::Object;
|
||||
|
||||
friend Group detail::make_group(hid_t);
|
||||
friend class File;
|
||||
friend class Reference;
|
||||
#if HIGHFIVE_HAS_FRIEND_DECLARATIONS
|
||||
template <typename Derivate>
|
||||
friend class ::HighFive::NodeTraits;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline std::pair<unsigned int, unsigned int> Group::getEstimatedLinkInfo() const {
|
||||
auto gcpl = getCreatePropertyList();
|
||||
auto eli = EstimatedLinkInfo(gcpl);
|
||||
return std::make_pair(eli.getEntries(), eli.getNameLength());
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
inline Group make_group(hid_t hid) {
|
||||
return Group(hid);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace HighFive
|
||||
139
include/highfive/H5Object.hpp
Normal file
139
include/highfive/H5Object.hpp
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <ctime>
|
||||
|
||||
#include "bits/H5_definitions.hpp"
|
||||
#include "bits/H5Friends.hpp"
|
||||
|
||||
#include "H5Exception.hpp"
|
||||
#include "bits/h5o_wrapper.hpp"
|
||||
#include "bits/h5i_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
///
|
||||
/// \brief Enum of the types of objects (H5O api)
|
||||
///
|
||||
enum class ObjectType {
|
||||
File,
|
||||
Group,
|
||||
UserDataType,
|
||||
DataSpace,
|
||||
Dataset,
|
||||
Attribute,
|
||||
Other // Internal/custom object type
|
||||
};
|
||||
|
||||
|
||||
class Object {
|
||||
public:
|
||||
// move constructor, reuse hid
|
||||
Object(Object&& other) noexcept;
|
||||
|
||||
///
|
||||
/// \brief isValid
|
||||
/// \return true if current Object is a valid HDF5Object
|
||||
///
|
||||
bool isValid() const noexcept;
|
||||
|
||||
///
|
||||
/// \brief getId
|
||||
/// \return internal HDF5 id to the object
|
||||
/// provided for C API compatibility
|
||||
///
|
||||
hid_t getId() const noexcept;
|
||||
|
||||
///
|
||||
/// \brief Retrieve several infos about the current object (address, dates, etc)
|
||||
///
|
||||
ObjectInfo getInfo() const;
|
||||
|
||||
///
|
||||
/// \brief Address of an HDF5 object in the file.
|
||||
///
|
||||
/// Not all HDF5 files support addresses anymore. The more recent concept
|
||||
/// is a VOL token.
|
||||
///
|
||||
/// \since 3.0.0
|
||||
///
|
||||
haddr_t getAddress() const;
|
||||
|
||||
///
|
||||
/// \brief Gets the fundamental type of the object (dataset, group, etc)
|
||||
/// \exception ObjectException when the _hid is negative or the type
|
||||
/// is custom and not registered yet
|
||||
///
|
||||
ObjectType getType() const;
|
||||
|
||||
// Check if refer to same object
|
||||
bool operator==(const Object& other) const noexcept {
|
||||
return _hid == other._hid;
|
||||
}
|
||||
|
||||
protected:
|
||||
// empty constructor
|
||||
Object();
|
||||
|
||||
// copy constructor, increase reference counter
|
||||
Object(const Object& other);
|
||||
|
||||
// Init with an low-level object id
|
||||
explicit Object(hid_t) noexcept;
|
||||
|
||||
// decrease reference counter
|
||||
~Object();
|
||||
|
||||
// Copy-Assignment operator
|
||||
Object& operator=(const Object& other);
|
||||
Object& operator=(Object&& other);
|
||||
|
||||
hid_t _hid;
|
||||
|
||||
private:
|
||||
friend class Reference;
|
||||
friend class CompoundType;
|
||||
|
||||
#if HIGHFIVE_HAS_FRIEND_DECLARATIONS
|
||||
template <typename Derivate>
|
||||
friend class NodeTraits;
|
||||
template <typename Derivate>
|
||||
friend class AnnotateTraits;
|
||||
template <typename Derivate>
|
||||
friend class PathTraits;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief A class for accessing hdf5 objects info
|
||||
///
|
||||
class ObjectInfo {
|
||||
public:
|
||||
ObjectInfo(const Object& obj);
|
||||
|
||||
/// \brief Retrieve the number of references to this object
|
||||
size_t getRefCount() const noexcept;
|
||||
|
||||
/// \brief Retrieve the object's creation time
|
||||
time_t getCreationTime() const noexcept;
|
||||
|
||||
/// \brief Retrieve the object's last modification time
|
||||
time_t getModificationTime() const noexcept;
|
||||
|
||||
private:
|
||||
detail::h5o_info1_t raw_info;
|
||||
|
||||
friend class Object;
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
|
||||
#include "bits/H5Object_misc.hpp"
|
||||
710
include/highfive/H5PropertyList.hpp
Normal file
710
include/highfive/H5PropertyList.hpp
Normal file
@ -0,0 +1,710 @@
|
||||
/*
|
||||
* Copyright (c), 2017-2018, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
* Juan Hernando <juan.hernando@epfl.ch>
|
||||
* 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 <vector>
|
||||
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
// Required by MPIOFileAccess
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
#include <H5FDmpi.h>
|
||||
#endif
|
||||
|
||||
#include "H5Exception.hpp"
|
||||
#include "H5Object.hpp"
|
||||
|
||||
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
|
||||
///
|
||||
enum class PropertyType : int {
|
||||
FILE_CREATE,
|
||||
FILE_ACCESS,
|
||||
DATASET_CREATE,
|
||||
DATASET_ACCESS,
|
||||
DATASET_XFER,
|
||||
GROUP_CREATE,
|
||||
GROUP_ACCESS,
|
||||
DATATYPE_CREATE,
|
||||
DATATYPE_ACCESS,
|
||||
STRING_CREATE,
|
||||
ATTRIBUTE_CREATE,
|
||||
LINK_CREATE,
|
||||
LINK_ACCESS,
|
||||
};
|
||||
|
||||
namespace details {
|
||||
template <typename T, typename U>
|
||||
T get_plist(const U& obj, hid_t (*f)(hid_t)) {
|
||||
auto hid = f(obj.getId());
|
||||
if (hid < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to get property list");
|
||||
}
|
||||
T t{};
|
||||
t._hid = hid;
|
||||
return t;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
///
|
||||
/// \brief Base Class for Property lists, providing global default
|
||||
class PropertyListBase: public Object {
|
||||
public:
|
||||
PropertyListBase() noexcept;
|
||||
|
||||
static const PropertyListBase& Default() noexcept {
|
||||
static const PropertyListBase plist{};
|
||||
return plist;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T, typename U>
|
||||
friend T details::get_plist(const U&, hid_t (*f)(hid_t));
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief HDF5 property Lists
|
||||
///
|
||||
template <PropertyType T>
|
||||
class PropertyList: public PropertyListBase {
|
||||
public:
|
||||
///
|
||||
/// \brief return the type of this PropertyList
|
||||
constexpr PropertyType getType() const noexcept {
|
||||
return T;
|
||||
}
|
||||
|
||||
///
|
||||
/// 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 <typename P>
|
||||
void add(const P& property);
|
||||
|
||||
///
|
||||
/// Return the Default property type object
|
||||
static const PropertyList<T>& Default() noexcept {
|
||||
return static_cast<const PropertyList<T>&>(PropertyListBase::Default());
|
||||
}
|
||||
|
||||
/// Return a property list created via a call to `H5Pcreate`.
|
||||
///
|
||||
/// An empty property is needed when one wants `getId()` to immediately
|
||||
/// point at a valid HID. This is important when interfacing directly with
|
||||
/// HDF5 to set properties that haven't been wrapped by HighFive.
|
||||
static PropertyList<T> Empty() {
|
||||
auto plist = PropertyList<T>();
|
||||
plist._initializeIfNeeded();
|
||||
|
||||
return plist;
|
||||
}
|
||||
|
||||
protected:
|
||||
void _initializeIfNeeded();
|
||||
};
|
||||
|
||||
using FileCreateProps = PropertyList<PropertyType::FILE_CREATE>;
|
||||
using FileAccessProps = PropertyList<PropertyType::FILE_ACCESS>;
|
||||
using DataSetCreateProps = PropertyList<PropertyType::DATASET_CREATE>;
|
||||
using DataSetAccessProps = PropertyList<PropertyType::DATASET_ACCESS>;
|
||||
using DataTransferProps = PropertyList<PropertyType::DATASET_XFER>;
|
||||
using GroupCreateProps = PropertyList<PropertyType::GROUP_CREATE>;
|
||||
using GroupAccessProps = PropertyList<PropertyType::GROUP_ACCESS>;
|
||||
using DataTypeCreateProps = PropertyList<PropertyType::DATATYPE_CREATE>;
|
||||
using DataTypeAccessProps = PropertyList<PropertyType::DATATYPE_ACCESS>;
|
||||
using StringCreateProps = PropertyList<PropertyType::STRING_CREATE>;
|
||||
using AttributeCreateProps = PropertyList<PropertyType::ATTRIBUTE_CREATE>;
|
||||
using LinkCreateProps = PropertyList<PropertyType::LINK_CREATE>;
|
||||
using LinkAccessProps = PropertyList<PropertyType::LINK_ACCESS>;
|
||||
|
||||
///
|
||||
/// RawPropertyLists are to be used when advanced H5 properties
|
||||
/// are desired and are not part of the HighFive API.
|
||||
/// Therefore this class is mainly for internal use.
|
||||
template <PropertyType T>
|
||||
class RawPropertyList: public PropertyList<T> {
|
||||
public:
|
||||
template <typename F, typename... Args>
|
||||
void add(const F& funct, const Args&... args);
|
||||
};
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
///
|
||||
/// \brief Configure MPI access for the file
|
||||
///
|
||||
/// All further modifications to the structure of the file will have to be
|
||||
/// done with collective operations
|
||||
///
|
||||
class MPIOFileAccess {
|
||||
public:
|
||||
MPIOFileAccess(MPI_Comm comm, MPI_Info info);
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
void apply(hid_t list) const;
|
||||
|
||||
MPI_Comm _comm;
|
||||
MPI_Info _info;
|
||||
};
|
||||
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 0)
|
||||
///
|
||||
/// \brief Use collective MPI-IO for metadata read and write.
|
||||
///
|
||||
/// See `MPIOCollectiveMetadataRead` and `MPIOCollectiveMetadataWrite`.
|
||||
///
|
||||
class MPIOCollectiveMetadata {
|
||||
public:
|
||||
explicit MPIOCollectiveMetadata(bool collective = true);
|
||||
explicit MPIOCollectiveMetadata(const FileAccessProps& plist);
|
||||
|
||||
bool isCollectiveRead() const;
|
||||
bool isCollectiveWrite() const;
|
||||
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
void apply(hid_t plist) const;
|
||||
|
||||
bool collective_read_;
|
||||
bool collective_write_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Use collective MPI-IO for metadata read?
|
||||
///
|
||||
/// Note that when used in a file access property list, this will force all reads
|
||||
/// of meta data to be collective. HDF5 function may implicitly perform metadata
|
||||
/// reads. These functions would become collective. A list of functions that
|
||||
/// perform metadata reads can be found in the HDF5 documentation, e.g.
|
||||
/// https://docs.hdfgroup.org/hdf5/v1_12/group___g_a_c_p_l.html
|
||||
///
|
||||
/// In HighFive setting collective read is (currently) only supported on file level.
|
||||
///
|
||||
/// Please also consult upstream documentation of `H5Pset_all_coll_metadata_ops`.
|
||||
///
|
||||
class MPIOCollectiveMetadataRead {
|
||||
public:
|
||||
explicit MPIOCollectiveMetadataRead(bool collective = true);
|
||||
explicit MPIOCollectiveMetadataRead(const FileAccessProps& plist);
|
||||
|
||||
bool isCollective() const;
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
friend MPIOCollectiveMetadata;
|
||||
|
||||
void apply(hid_t plist) const;
|
||||
|
||||
bool collective_;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Use collective MPI-IO for metadata write?
|
||||
///
|
||||
/// In order to keep the in-memory representation of the file structure
|
||||
/// consistent across MPI ranks, writing meta data is always a collective
|
||||
/// operation. Meaning all MPI ranks must participate. Passing this setting
|
||||
/// enables using MPI-IO collective operations for metadata writes.
|
||||
///
|
||||
/// Please also consult upstream documentation of `H5Pset_coll_metadata_write`.
|
||||
///
|
||||
class MPIOCollectiveMetadataWrite {
|
||||
public:
|
||||
explicit MPIOCollectiveMetadataWrite(bool collective = true);
|
||||
explicit MPIOCollectiveMetadataWrite(const FileAccessProps& plist);
|
||||
|
||||
bool isCollective() const;
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
friend MPIOCollectiveMetadata;
|
||||
|
||||
void apply(hid_t plist) const;
|
||||
|
||||
bool collective_;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///
|
||||
/// \brief Configure the version bounds for the file
|
||||
///
|
||||
/// Used to define the compatibility of objects created within HDF5 files,
|
||||
/// and affects the format of groups stored in the file.
|
||||
///
|
||||
/// See also the documentation of \c H5P_SET_LIBVER_BOUNDS in HDF5.
|
||||
///
|
||||
/// Possible values for \c low and \c high are:
|
||||
/// * \c H5F_LIBVER_EARLIEST
|
||||
/// * \c H5F_LIBVER_V18
|
||||
/// * \c H5F_LIBVER_V110
|
||||
/// * \c H5F_LIBVER_NBOUNDS
|
||||
/// * \c H5F_LIBVER_LATEST currently defined as \c H5F_LIBVER_V110 within
|
||||
/// HDF5
|
||||
///
|
||||
class FileVersionBounds {
|
||||
public:
|
||||
FileVersionBounds(H5F_libver_t low, H5F_libver_t high);
|
||||
explicit FileVersionBounds(const FileAccessProps& fapl);
|
||||
|
||||
std::pair<H5F_libver_t, H5F_libver_t> getVersion() const;
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
void apply(hid_t list) const;
|
||||
|
||||
H5F_libver_t _low;
|
||||
H5F_libver_t _high;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Configure the metadata block size to use writing to files
|
||||
///
|
||||
/// \param size Metadata block size in bytes
|
||||
///
|
||||
class MetadataBlockSize {
|
||||
public:
|
||||
explicit MetadataBlockSize(hsize_t size);
|
||||
explicit MetadataBlockSize(const FileAccessProps& fapl);
|
||||
|
||||
hsize_t getSize() const;
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
void apply(hid_t list) const;
|
||||
hsize_t _size;
|
||||
};
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 1)
|
||||
///
|
||||
/// \brief Configure the file space strategy.
|
||||
///
|
||||
/// See the upstream documentation of `H5Pget_file_space_strategy` for more details. Essentially,
|
||||
/// it enables configuring how space is allocate in the file.
|
||||
///
|
||||
class FileSpaceStrategy {
|
||||
public:
|
||||
///
|
||||
/// \brief Create a file space strategy property.
|
||||
///
|
||||
/// \param strategy The HDF5 free space strategy.
|
||||
/// \param persist Should free space managers be persisted across file closing and reopening.
|
||||
/// \param threshold The free-space manager wont track sections small than this threshold.
|
||||
FileSpaceStrategy(H5F_fspace_strategy_t strategy, hbool_t persist, hsize_t threshold);
|
||||
explicit FileSpaceStrategy(const FileCreateProps& fcpl);
|
||||
|
||||
H5F_fspace_strategy_t getStrategy() const;
|
||||
hbool_t getPersist() const;
|
||||
hsize_t getThreshold() const;
|
||||
|
||||
private:
|
||||
friend FileCreateProps;
|
||||
|
||||
void apply(hid_t list) const;
|
||||
|
||||
H5F_fspace_strategy_t _strategy;
|
||||
hbool_t _persist;
|
||||
hsize_t _threshold;
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Configure the page size for paged allocation.
|
||||
///
|
||||
/// See the upstream documentation of `H5Pset_file_space_page_size` for more details. Essentially,
|
||||
/// it enables configuring the page size when paged allocation is used.
|
||||
///
|
||||
/// General information about paged allocation can be found in the upstream documentation "RFC: Page
|
||||
/// Buffering".
|
||||
///
|
||||
class FileSpacePageSize {
|
||||
public:
|
||||
///
|
||||
/// \brief Create a file space strategy property.
|
||||
///
|
||||
/// \param page_size The page size in bytes.
|
||||
explicit FileSpacePageSize(hsize_t page_size);
|
||||
explicit FileSpacePageSize(const FileCreateProps& fcpl);
|
||||
|
||||
hsize_t getPageSize() const;
|
||||
|
||||
private:
|
||||
friend FileCreateProps;
|
||||
void apply(hid_t list) const;
|
||||
|
||||
hsize_t _page_size;
|
||||
};
|
||||
|
||||
#ifndef H5_HAVE_PARALLEL
|
||||
/// \brief Set size of the page buffer.
|
||||
///
|
||||
/// Please, consult the upstream documentation of
|
||||
/// H5Pset_page_buffer_size
|
||||
/// H5Pget_page_buffer_size
|
||||
/// Note that this setting is only valid for page allocated/aggregated
|
||||
/// files, i.e. those that have file space strategy "Page".
|
||||
///
|
||||
/// Tests suggest this doesn't work in the parallel version of the
|
||||
/// library. Hence, this isn't available at compile time if the parallel
|
||||
/// library was selected.
|
||||
class PageBufferSize {
|
||||
public:
|
||||
/// Property to set page buffer sizes.
|
||||
///
|
||||
/// @param page_buffer_size maximum size of the page buffer in bytes.
|
||||
/// @param min_meta_percent fraction of the page buffer dedicated to meta data, in percent.
|
||||
/// @param min_raw_percent fraction of the page buffer dedicated to raw data, in percent.
|
||||
explicit PageBufferSize(size_t page_buffer_size,
|
||||
unsigned min_meta_percent = 0,
|
||||
unsigned min_raw_percent = 0);
|
||||
|
||||
explicit PageBufferSize(const FileAccessProps& fapl);
|
||||
|
||||
size_t getPageBufferSize() const;
|
||||
unsigned getMinMetaPercent() const;
|
||||
unsigned getMinRawPercent() const;
|
||||
|
||||
private:
|
||||
friend FileAccessProps;
|
||||
|
||||
void apply(hid_t list) const;
|
||||
|
||||
size_t _page_buffer_size;
|
||||
unsigned _min_meta;
|
||||
unsigned _min_raw;
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/// \brief Set hints as to how many links to expect and their average length
|
||||
///
|
||||
class EstimatedLinkInfo {
|
||||
public:
|
||||
/// \brief Create a property with the request parameters.
|
||||
///
|
||||
/// @param entries The estimated number of links in a group.
|
||||
/// @param length The estimated length of the names of links.
|
||||
explicit EstimatedLinkInfo(unsigned entries, unsigned length);
|
||||
|
||||
explicit EstimatedLinkInfo(const GroupCreateProps& gcpl);
|
||||
|
||||
/// \brief The estimated number of links in a group.
|
||||
unsigned getEntries() const;
|
||||
|
||||
/// \brief The estimated length of the names of links.
|
||||
unsigned getNameLength() const;
|
||||
|
||||
private:
|
||||
friend GroupCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
unsigned _entries;
|
||||
unsigned _length;
|
||||
};
|
||||
|
||||
|
||||
class Chunking {
|
||||
public:
|
||||
explicit Chunking(const std::vector<hsize_t>& dims);
|
||||
Chunking(const std::initializer_list<hsize_t>& items);
|
||||
|
||||
template <typename... Args>
|
||||
explicit Chunking(hsize_t item, Args... args);
|
||||
|
||||
explicit Chunking(DataSetCreateProps& plist, size_t max_dims = 32);
|
||||
|
||||
const std::vector<hsize_t>& getDimensions() const;
|
||||
|
||||
private:
|
||||
friend DataSetCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
std::vector<hsize_t> _dims;
|
||||
};
|
||||
|
||||
class Deflate {
|
||||
public:
|
||||
explicit Deflate(unsigned level);
|
||||
|
||||
private:
|
||||
friend DataSetCreateProps;
|
||||
friend GroupCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
const unsigned _level;
|
||||
};
|
||||
|
||||
class Szip {
|
||||
public:
|
||||
explicit Szip(unsigned options_mask = H5_SZIP_EC_OPTION_MASK,
|
||||
unsigned pixels_per_block = H5_SZIP_MAX_PIXELS_PER_BLOCK);
|
||||
|
||||
unsigned getOptionsMask() const;
|
||||
unsigned getPixelsPerBlock() const;
|
||||
|
||||
private:
|
||||
friend DataSetCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
const unsigned _options_mask;
|
||||
const unsigned _pixels_per_block;
|
||||
};
|
||||
|
||||
class Shuffle {
|
||||
public:
|
||||
Shuffle() = default;
|
||||
|
||||
private:
|
||||
friend DataSetCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
};
|
||||
|
||||
/// \brief When are datasets allocated?
|
||||
///
|
||||
/// The precise time of when HDF5 requests space to store the dataset
|
||||
/// can be configured. Please, consider the upstream documentation for
|
||||
/// `H5Pset_alloc_time`.
|
||||
class AllocationTime {
|
||||
public:
|
||||
explicit AllocationTime(H5D_alloc_time_t alloc_time);
|
||||
explicit AllocationTime(const DataSetCreateProps& dcpl);
|
||||
|
||||
H5D_alloc_time_t getAllocationTime();
|
||||
|
||||
private:
|
||||
friend DataSetCreateProps;
|
||||
void apply(hid_t dcpl) const;
|
||||
|
||||
H5D_alloc_time_t _alloc_time;
|
||||
};
|
||||
|
||||
/// Dataset access property to control chunk cache configuration.
|
||||
/// Do not confuse with the similar file access property for H5Pset_cache
|
||||
class Caching {
|
||||
public:
|
||||
/// https://support.hdfgroup.org/HDF5/doc/RM/H5P/H5Pset_chunk_cache.html for
|
||||
/// details.
|
||||
Caching(size_t numSlots,
|
||||
size_t cacheSize,
|
||||
double w0 = static_cast<double>(H5D_CHUNK_CACHE_W0_DEFAULT));
|
||||
|
||||
explicit Caching(const DataSetCreateProps& dcpl);
|
||||
|
||||
size_t getNumSlots() const;
|
||||
size_t getCacheSize() const;
|
||||
double getW0() const;
|
||||
|
||||
private:
|
||||
friend DataSetAccessProps;
|
||||
void apply(hid_t hid) const;
|
||||
size_t _numSlots;
|
||||
size_t _cacheSize;
|
||||
double _w0;
|
||||
};
|
||||
|
||||
class CreateIntermediateGroup {
|
||||
public:
|
||||
explicit CreateIntermediateGroup(bool create = true);
|
||||
|
||||
explicit CreateIntermediateGroup(const LinkCreateProps& lcpl);
|
||||
|
||||
bool isSet() const;
|
||||
|
||||
protected:
|
||||
void fromPropertyList(hid_t hid);
|
||||
|
||||
private:
|
||||
friend LinkCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
bool _create;
|
||||
};
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
class UseCollectiveIO {
|
||||
public:
|
||||
explicit UseCollectiveIO(bool enable = true);
|
||||
|
||||
explicit UseCollectiveIO(const DataTransferProps& dxpl);
|
||||
|
||||
/// \brief Does the property request collective IO?
|
||||
bool isCollective() const;
|
||||
|
||||
private:
|
||||
friend DataTransferProps;
|
||||
void apply(hid_t hid) const;
|
||||
bool _enable;
|
||||
};
|
||||
|
||||
|
||||
/// \brief The cause for non-collective I/O.
|
||||
///
|
||||
/// The cause refers to the most recent I/O with data transfer property list `dxpl` at time of
|
||||
/// 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`.
|
||||
class MpioNoCollectiveCause {
|
||||
public:
|
||||
explicit MpioNoCollectiveCause(const DataTransferProps& dxpl);
|
||||
|
||||
/// \brief Was the datatransfer collective?
|
||||
bool wasCollective() const;
|
||||
|
||||
/// \brief The local cause for a non-collective I/O.
|
||||
uint32_t getLocalCause() const;
|
||||
|
||||
/// \brief The global cause for a non-collective I/O.
|
||||
uint32_t getGlobalCause() const;
|
||||
|
||||
/// \brief A pair of the local and global cause for non-collective I/O.
|
||||
std::pair<uint32_t, uint32_t> getCause() const;
|
||||
|
||||
private:
|
||||
friend DataTransferProps;
|
||||
uint32_t _local_cause;
|
||||
uint32_t _global_cause;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct CreationOrder {
|
||||
enum _creation_order {
|
||||
Tracked = H5P_CRT_ORDER_TRACKED,
|
||||
Indexed = H5P_CRT_ORDER_INDEXED,
|
||||
};
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Track and index creation order time
|
||||
///
|
||||
/// Let user retrieve objects by creation order time instead of name.
|
||||
///
|
||||
class LinkCreationOrder {
|
||||
public:
|
||||
///
|
||||
/// \brief Create the property
|
||||
/// \param flags Should be a composition of HighFive::CreationOrder.
|
||||
///
|
||||
explicit LinkCreationOrder(unsigned flags)
|
||||
: _flags(flags) {}
|
||||
|
||||
explicit LinkCreationOrder(const FileCreateProps& fcpl);
|
||||
explicit LinkCreationOrder(const GroupCreateProps& gcpl);
|
||||
|
||||
unsigned getFlags() const;
|
||||
|
||||
protected:
|
||||
void fromPropertyList(hid_t hid);
|
||||
|
||||
private:
|
||||
friend FileCreateProps;
|
||||
friend GroupCreateProps;
|
||||
void apply(hid_t hid) const;
|
||||
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.
|
||||
///
|
||||
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"
|
||||
81
include/highfive/H5Reference.hpp
Normal file
81
include/highfive/H5Reference.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c), 2020, EPFL - 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
#include <H5Rpublic.h>
|
||||
|
||||
#include "bits/H5_definitions.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace details {
|
||||
template <typename T>
|
||||
struct inspector;
|
||||
}
|
||||
///
|
||||
/// \brief An HDF5 (object) reference type
|
||||
///
|
||||
/// HDF5 object references allow pointing to groups, datasets (and compound types). They
|
||||
/// differ from links in their ability to be stored and retrieved as data from the HDF5
|
||||
/// file in datasets themselves.
|
||||
///
|
||||
class Reference {
|
||||
public:
|
||||
/// \brief Create an empty Reference to be initialized later
|
||||
Reference() = default;
|
||||
|
||||
/// \brief Create a Reference to an object residing at a given location
|
||||
///
|
||||
/// \param location A File or Group where the object being referenced to resides
|
||||
/// \param object A Dataset or Group to be referenced
|
||||
Reference(const Object& location, const Object& object);
|
||||
|
||||
/// \brief Retrieve the Object being referenced by the Reference
|
||||
///
|
||||
/// \tparam T the appropriate HighFive Container (either DataSet or Group)
|
||||
/// \param location the location where the referenced object is to be found (a File)
|
||||
/// \return the dereferenced Object (either a Group or DataSet)
|
||||
template <typename T>
|
||||
T dereference(const Object& location) const;
|
||||
|
||||
/// \brief Get only the type of the referenced Object
|
||||
///
|
||||
/// \param location the location where the referenced object is to be found (a File)
|
||||
/// \return the ObjectType of the referenced object
|
||||
ObjectType getType(const Object& location) const;
|
||||
|
||||
protected:
|
||||
/// \brief Create a Reference from a low-level HDF5 object reference
|
||||
inline explicit Reference(const hobj_ref_t h5_ref)
|
||||
: href(h5_ref) {};
|
||||
|
||||
/// \brief Create the low-level reference and store it at refptr
|
||||
///
|
||||
/// \param refptr Pointer to a memory location where the created HDF5 reference will
|
||||
/// be stored
|
||||
void create_ref(hobj_ref_t* refptr) const;
|
||||
|
||||
private:
|
||||
Object get_ref(const Object& location) const;
|
||||
|
||||
hobj_ref_t href{};
|
||||
std::string obj_name{};
|
||||
hid_t parent_id{};
|
||||
|
||||
friend struct details::inspector<Reference>;
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
|
||||
#include "bits/H5Reference_misc.hpp"
|
||||
68
include/highfive/H5Selection.hpp
Normal file
68
include/highfive/H5Selection.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "H5DataSet.hpp"
|
||||
#include "H5DataSpace.hpp"
|
||||
#include "bits/H5Slice_traits.hpp"
|
||||
#include "bits/H5Friends.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace detail {
|
||||
Selection make_selection(const DataSpace&, const DataSpace&, const DataSet&);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Selection: represent a view on a slice/part of a dataset
|
||||
///
|
||||
/// A Selection is valid only if its parent dataset is valid
|
||||
///
|
||||
class Selection: public SliceTraits<Selection> {
|
||||
public:
|
||||
///
|
||||
/// \brief getSpace
|
||||
/// \return Dataspace associated with this selection
|
||||
///
|
||||
DataSpace getSpace() const;
|
||||
|
||||
///
|
||||
/// \brief getMemSpace
|
||||
/// \return Dataspace associated with the memory representation of this
|
||||
/// selection
|
||||
///
|
||||
DataSpace getMemSpace() const;
|
||||
|
||||
///
|
||||
/// \brief getDataSet
|
||||
/// \return parent dataset of this selection
|
||||
///
|
||||
DataSet& getDataset();
|
||||
const DataSet& getDataset() const;
|
||||
|
||||
///
|
||||
/// \brief return the datatype of the selection
|
||||
/// \return return the datatype of the selection
|
||||
DataType getDataType() const;
|
||||
|
||||
protected:
|
||||
Selection(const DataSpace& memspace, const DataSpace& file_space, const DataSet& set);
|
||||
|
||||
private:
|
||||
DataSpace _mem_space, _file_space;
|
||||
DataSet _set;
|
||||
|
||||
#if HIGHFIVE_HAS_FRIEND_DECLARATIONS
|
||||
template <typename Derivate>
|
||||
friend class ::HighFive::SliceTraits;
|
||||
#endif
|
||||
friend Selection detail::make_selection(const DataSpace&, const DataSpace&, const DataSet&);
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
218
include/highfive/H5Utility.hpp
Normal file
218
include/highfive/H5Utility.hpp
Normal file
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Blue Brain Project - EPFL (CH)
|
||||
*
|
||||
* 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 <functional>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "bits/h5e_wrapper.hpp"
|
||||
#include "bits/H5Friends.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
///
|
||||
/// \brief Utility class to disable HDF5 stack printing inside a scope.
|
||||
///
|
||||
class SilenceHDF5 {
|
||||
public:
|
||||
inline explicit SilenceHDF5(bool enable = true)
|
||||
: _client_data(nullptr) {
|
||||
detail::nothrow::h5e_get_auto2(H5E_DEFAULT, &_func, &_client_data);
|
||||
|
||||
if (enable) {
|
||||
detail::nothrow::h5e_set_auto2(H5E_DEFAULT, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
inline ~SilenceHDF5() {
|
||||
detail::nothrow::h5e_set_auto2(H5E_DEFAULT, _func, _client_data);
|
||||
}
|
||||
|
||||
private:
|
||||
H5E_auto2_t _func;
|
||||
void* _client_data;
|
||||
};
|
||||
|
||||
#define HIGHFIVE_LOG_LEVEL_DEBUG 10
|
||||
#define HIGHFIVE_LOG_LEVEL_INFO 20
|
||||
#define HIGHFIVE_LOG_LEVEL_WARN 30
|
||||
#define HIGHFIVE_LOG_LEVEL_ERROR 40
|
||||
|
||||
#ifndef HIGHFIVE_LOG_LEVEL
|
||||
#define HIGHFIVE_LOG_LEVEL HIGHFIVE_LOG_LEVEL_WARN
|
||||
#endif
|
||||
|
||||
enum class LogSeverity {
|
||||
Debug = HIGHFIVE_LOG_LEVEL_DEBUG,
|
||||
Info = HIGHFIVE_LOG_LEVEL_INFO,
|
||||
Warn = HIGHFIVE_LOG_LEVEL_WARN,
|
||||
Error = HIGHFIVE_LOG_LEVEL_ERROR
|
||||
};
|
||||
|
||||
inline std::string to_string(LogSeverity severity) {
|
||||
switch (severity) {
|
||||
case LogSeverity::Debug:
|
||||
return "DEBUG";
|
||||
case LogSeverity::Info:
|
||||
return "INFO";
|
||||
case LogSeverity::Warn:
|
||||
return "WARN";
|
||||
case LogSeverity::Error:
|
||||
return "ERROR";
|
||||
default:
|
||||
return "??";
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief A logger with supporting basic functionality.
|
||||
*
|
||||
* This logger delegates the logging task to a callback. This level of
|
||||
* indirection enables using the default Python logger from C++; or
|
||||
* integrating HighFive into some custom logging solution.
|
||||
*
|
||||
* Using this class directly to log is not intended. Rather you should use
|
||||
* - `HIGHFIVE_LOG_DEBUG{,_IF}`
|
||||
* - `HIGHFIVE_LOG_INFO{,_IF}`
|
||||
* - `HIGHFIVE_LOG_WARNING{,_IF}`
|
||||
* - `HIGHFIVE_LOG_ERROR{,_IF}`
|
||||
*
|
||||
* This is intended to used as a singleton, via `get_global_logger()`.
|
||||
*/
|
||||
class Logger {
|
||||
public:
|
||||
using callback_type =
|
||||
std::function<void(LogSeverity, const std::string&, const std::string&, int)>;
|
||||
|
||||
public:
|
||||
Logger() = delete;
|
||||
Logger(const Logger&) = delete;
|
||||
Logger(Logger&&) = delete;
|
||||
|
||||
explicit Logger(callback_type cb)
|
||||
: _cb(std::move(cb)) {}
|
||||
|
||||
Logger& operator=(const Logger&) = delete;
|
||||
Logger& operator=(Logger&&) = delete;
|
||||
|
||||
inline void log(LogSeverity severity,
|
||||
const std::string& message,
|
||||
const std::string& file,
|
||||
int line) {
|
||||
_cb(severity, message, file, line);
|
||||
}
|
||||
|
||||
inline void set_logging_callback(callback_type cb) {
|
||||
_cb = std::move(cb);
|
||||
}
|
||||
|
||||
private:
|
||||
callback_type _cb;
|
||||
};
|
||||
|
||||
inline void default_logging_callback(LogSeverity severity,
|
||||
const std::string& message,
|
||||
const std::string& file,
|
||||
int line) {
|
||||
std::clog << file << ": " << line << " [" << to_string(severity) << "] " << message
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
/// \brief Obtain a reference to the logger used by HighFive.
|
||||
///
|
||||
/// This uses a Meyers singleton, to ensure that the global logger is
|
||||
/// initialized with a safe default logger, before it is used.
|
||||
///
|
||||
/// Note: You probably don't need to call this function explicitly.
|
||||
///
|
||||
inline Logger& get_global_logger() {
|
||||
static Logger logger(&default_logging_callback);
|
||||
return logger;
|
||||
}
|
||||
|
||||
/// \brief Sets the callback that's used by the logger.
|
||||
inline void register_logging_callback(Logger::callback_type cb) {
|
||||
auto& logger = get_global_logger();
|
||||
logger.set_logging_callback(std::move(cb));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
/// \brief Log a `message` with severity `severity`.
|
||||
inline void log(LogSeverity severity,
|
||||
const std::string& message,
|
||||
const std::string& file,
|
||||
int line) {
|
||||
auto& logger = get_global_logger();
|
||||
logger.log(severity, message, file, line);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
#if HIGHFIVE_LOG_LEVEL <= HIGHFIVE_LOG_LEVEL_DEBUG
|
||||
#define HIGHFIVE_LOG_DEBUG(message) \
|
||||
::HighFive::detail::log(::HighFive::LogSeverity::Debug, (message), __FILE__, __LINE__);
|
||||
|
||||
// Useful, for the common pattern: if ...; then log something.
|
||||
#define HIGHFIVE_LOG_DEBUG_IF(cond, message) \
|
||||
if ((cond)) { \
|
||||
HIGHFIVE_LOG_DEBUG((message)); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define HIGHFIVE_LOG_DEBUG(message) ;
|
||||
#define HIGHFIVE_LOG_DEBUG_IF(cond, message) ;
|
||||
#endif
|
||||
|
||||
#if HIGHFIVE_LOG_LEVEL <= HIGHFIVE_LOG_LEVEL_INFO
|
||||
#define HIGHFIVE_LOG_INFO(message) \
|
||||
::HighFive::detail::log(::HighFive::LogSeverity::Info, (message), __FILE__, __LINE__);
|
||||
|
||||
// Useful, for the common pattern: if ...; then log something.
|
||||
#define HIGHFIVE_LOG_INFO_IF(cond, message) \
|
||||
if ((cond)) { \
|
||||
HIGHFIVE_LOG_INFO((message)); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define HIGHFIVE_LOG_INFO(message) ;
|
||||
#define HIGHFIVE_LOG_INFO_IF(cond, message) ;
|
||||
#endif
|
||||
|
||||
|
||||
#if HIGHFIVE_LOG_LEVEL <= HIGHFIVE_LOG_LEVEL_WARN
|
||||
#define HIGHFIVE_LOG_WARN(message) \
|
||||
::HighFive::detail::log(::HighFive::LogSeverity::Warn, (message), __FILE__, __LINE__);
|
||||
|
||||
// Useful, for the common pattern: if ...; then log something.
|
||||
#define HIGHFIVE_LOG_WARN_IF(cond, message) \
|
||||
if ((cond)) { \
|
||||
HIGHFIVE_LOG_WARN((message)); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define HIGHFIVE_LOG_WARN(message) ;
|
||||
#define HIGHFIVE_LOG_WARN_IF(cond, message) ;
|
||||
#endif
|
||||
|
||||
#if HIGHFIVE_LOG_LEVEL <= HIGHFIVE_LOG_LEVEL_ERROR
|
||||
#define HIGHFIVE_LOG_ERROR(message) \
|
||||
::HighFive::detail::log(::HighFive::LogSeverity::Error, (message), __FILE__, __LINE__);
|
||||
|
||||
// Useful, for the common pattern: if ...; then log something.
|
||||
#define HIGHFIVE_LOG_ERROR_IF(cond, message) \
|
||||
if ((cond)) { \
|
||||
HIGHFIVE_LOG_ERROR((message)); \
|
||||
}
|
||||
|
||||
#else
|
||||
#define HIGHFIVE_LOG_ERROR(message) ;
|
||||
#define HIGHFIVE_LOG_ERROR_IF(cond, message) ;
|
||||
#endif
|
||||
|
||||
} // namespace HighFive
|
||||
33
include/highfive/H5Version.hpp
Normal file
33
include/highfive/H5Version.hpp
Normal file
@ -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 3
|
||||
#define HIGHFIVE_VERSION_MINOR 0
|
||||
#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 3.0.0
|
||||
|
||||
/** \brief String representation of the HighFive version.
|
||||
*
|
||||
* \warning This macro only exists from 2.7.1 onwards.
|
||||
*/
|
||||
#define HIGHFIVE_VERSION_STRING "3.0.0"
|
||||
81
include/highfive/bits/H5Annotate_traits.hpp
Normal file
81
include/highfive/bits/H5Annotate_traits.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
|
||||
#include "../H5Attribute.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <typename Derivate>
|
||||
class AnnotateTraits {
|
||||
public:
|
||||
///
|
||||
/// \brief create a new attribute with the name attribute_name
|
||||
/// \param attribute_name identifier of the attribute
|
||||
/// \param space Associated \ref DataSpace
|
||||
/// \param type
|
||||
/// \return the attribute object
|
||||
///
|
||||
Attribute createAttribute(const std::string& attribute_name,
|
||||
const DataSpace& space,
|
||||
const DataType& type);
|
||||
|
||||
///
|
||||
/// \brief createAttribute create a new attribute on the current dataset with
|
||||
/// size specified by space
|
||||
/// \param attribute_name identifier of the attribute
|
||||
/// \param space Associated DataSpace
|
||||
/// informations
|
||||
/// \return Attribute Object
|
||||
template <typename Type>
|
||||
Attribute createAttribute(const std::string& attribute_name, const DataSpace& space);
|
||||
|
||||
///
|
||||
/// \brief createAttribute create a new attribute on the current dataset and
|
||||
/// write to it, inferring the DataSpace from data.
|
||||
/// \param attribute_name identifier of the attribute
|
||||
/// \param data Associated data to write, must support DataSpace::From, see
|
||||
/// \ref DataSpace for more information
|
||||
/// \return Attribute Object
|
||||
///
|
||||
template <typename T>
|
||||
Attribute createAttribute(const std::string& attribute_name, const T& data);
|
||||
|
||||
///
|
||||
/// \brief deleteAttribute let you delete an attribute by its name.
|
||||
/// \param attribute_name identifier of the attribute
|
||||
void deleteAttribute(const std::string& attribute_name);
|
||||
|
||||
///
|
||||
/// \brief open an existing attribute with the name attribute_name
|
||||
/// \param attribute_name identifier of the attribute
|
||||
/// \return the attribute object
|
||||
Attribute getAttribute(const std::string& attribute_name) const;
|
||||
|
||||
///
|
||||
/// \brief return the number of attributes of the node / group
|
||||
/// \return number of attributes
|
||||
size_t getNumberAttributes() const;
|
||||
|
||||
///
|
||||
/// \brief list all attribute name of the node / group
|
||||
/// \return number of attributes
|
||||
std::vector<std::string> listAttributeNames() const;
|
||||
|
||||
///
|
||||
/// \brief checks an attribute exists
|
||||
/// \return number of attributes
|
||||
bool hasAttribute(const std::string& attr_name) const;
|
||||
|
||||
private:
|
||||
using derivate_type = Derivate;
|
||||
};
|
||||
} // namespace HighFive
|
||||
97
include/highfive/bits/H5Annotate_traits_misc.hpp
Normal file
97
include/highfive/bits/H5Annotate_traits_misc.hpp
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <H5Apublic.h>
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
#include "H5Attribute_misc.hpp"
|
||||
#include "H5Iterables_misc.hpp"
|
||||
#include "h5a_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <typename Derivate>
|
||||
inline Attribute AnnotateTraits<Derivate>::createAttribute(const std::string& attribute_name,
|
||||
const DataSpace& space,
|
||||
const DataType& dtype) {
|
||||
auto attr_id = detail::h5a_create2(static_cast<Derivate*>(this)->getId(),
|
||||
attribute_name.c_str(),
|
||||
dtype.getId(),
|
||||
space.getId(),
|
||||
H5P_DEFAULT,
|
||||
H5P_DEFAULT);
|
||||
return detail::make_attribute(attr_id);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename Type>
|
||||
inline Attribute AnnotateTraits<Derivate>::createAttribute(const std::string& attribute_name,
|
||||
const DataSpace& space) {
|
||||
return createAttribute(attribute_name, space, create_and_check_datatype<Type>());
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline Attribute AnnotateTraits<Derivate>::createAttribute(const std::string& attribute_name,
|
||||
const T& data) {
|
||||
Attribute att =
|
||||
createAttribute(attribute_name,
|
||||
DataSpace::From(data),
|
||||
create_and_check_datatype<typename details::inspector<T>::base_type>());
|
||||
att.write(data);
|
||||
return att;
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline void AnnotateTraits<Derivate>::deleteAttribute(const std::string& attribute_name) {
|
||||
detail::h5a_delete(static_cast<const Derivate*>(this)->getId(), attribute_name.c_str());
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Attribute AnnotateTraits<Derivate>::getAttribute(const std::string& attribute_name) const {
|
||||
const auto attr_id = detail::h5a_open(static_cast<const Derivate*>(this)->getId(),
|
||||
attribute_name.c_str(),
|
||||
H5P_DEFAULT);
|
||||
return detail::make_attribute(attr_id);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline size_t AnnotateTraits<Derivate>::getNumberAttributes() const {
|
||||
int res = detail::h5a_get_num_attrs(static_cast<const Derivate*>(this)->getId());
|
||||
return static_cast<size_t>(res);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline std::vector<std::string> AnnotateTraits<Derivate>::listAttributeNames() const {
|
||||
std::vector<std::string> names;
|
||||
details::HighFiveIterateData iterateData(names);
|
||||
|
||||
size_t num_objs = getNumberAttributes();
|
||||
names.reserve(num_objs);
|
||||
|
||||
detail::h5a_iterate2(static_cast<const Derivate*>(this)->getId(),
|
||||
H5_INDEX_NAME,
|
||||
H5_ITER_INC,
|
||||
nullptr,
|
||||
&details::internal_high_five_iterate<H5A_info_t>,
|
||||
static_cast<void*>(&iterateData));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline bool AnnotateTraits<Derivate>::hasAttribute(const std::string& attr_name) const {
|
||||
return detail::h5a_exists(static_cast<const Derivate*>(this)->getId(), attr_name.c_str()) > 0;
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
183
include/highfive/bits/H5Attribute_misc.hpp
Normal file
183
include/highfive/bits/H5Attribute_misc.hpp
Normal file
@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Ali Can Demiralp <ali.demiralp@rwth-aachen.de>
|
||||
*
|
||||
* 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 <H5Ipublic.h>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
#include "../H5DataSpace.hpp"
|
||||
#include "H5Converter_misc.hpp"
|
||||
#include "H5Inspector_misc.hpp"
|
||||
#include "H5ReadWrite_misc.hpp"
|
||||
#include "H5Utils.hpp"
|
||||
#include "h5a_wrapper.hpp"
|
||||
#include "h5d_wrapper.hpp"
|
||||
#include "squeeze.hpp"
|
||||
#include "assert_compatible_spaces.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline std::string Attribute::getName() const {
|
||||
return details::get_name(
|
||||
[&](char* buffer, size_t length) { return detail::h5a_get_name(_hid, length, buffer); });
|
||||
}
|
||||
|
||||
inline size_t Attribute::getStorageSize() const {
|
||||
if (!this->isValid()) {
|
||||
throw AttributeException("Invalid call to `DataSet::getFile` for invalid object");
|
||||
}
|
||||
|
||||
return static_cast<size_t>(detail::h5a_get_storage_size(_hid));
|
||||
}
|
||||
|
||||
inline DataType Attribute::getDataType() const {
|
||||
DataType res;
|
||||
res._hid = detail::h5a_get_type(_hid);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline DataSpace Attribute::getSpace() const {
|
||||
DataSpace space;
|
||||
space._hid = detail::h5a_get_space(_hid);
|
||||
return space;
|
||||
}
|
||||
|
||||
inline DataSpace Attribute::getMemSpace() const {
|
||||
return _mem_space.getId() == H5I_INVALID_HID ? getSpace() : _mem_space;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Attribute::read() const {
|
||||
T array;
|
||||
read(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::read(T& array) const {
|
||||
const DataSpace& mem_space = getMemSpace();
|
||||
auto file_datatype = getDataType();
|
||||
const details::BufferInfo<T> buffer_info(
|
||||
file_datatype,
|
||||
[this]() -> std::string { return this->getName(); },
|
||||
details::BufferInfo<T>::Operation::read);
|
||||
|
||||
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
|
||||
std::ostringstream ss;
|
||||
ss << "Impossible to read attribute of dimensions " << mem_space.getNumberDimensions()
|
||||
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
|
||||
<< buffer_info.getMaxRank() << "(max)";
|
||||
throw DataSpaceException(ss.str());
|
||||
}
|
||||
auto dims = mem_space.getDimensions();
|
||||
|
||||
if (mem_space.getElementCount() == 0) {
|
||||
details::inspector<T>::prepare(array, dims);
|
||||
return;
|
||||
}
|
||||
|
||||
auto r = details::data_converter::get_reader<T>(dims, array, file_datatype);
|
||||
read_raw(r.getPointer(), buffer_info.data_type);
|
||||
// re-arrange results
|
||||
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) detail::h5t_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer());
|
||||
#else
|
||||
// This one is deprecated since 1.12.0
|
||||
(void) detail::h5d_vlen_reclaim(t.getId(), mem_space.getId(), H5P_DEFAULT, r.getPointer());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::read_raw(T* array, const DataType& mem_datatype) const {
|
||||
static_assert(!std::is_const<T>::value,
|
||||
"read() requires a non-const structure to read data into");
|
||||
|
||||
detail::h5a_read(getId(), mem_datatype.getId(), static_cast<void*>(array));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::read_raw(T* array) const {
|
||||
using element_type = typename details::inspector<T>::base_type;
|
||||
const DataType& mem_datatype = create_and_check_datatype<element_type>();
|
||||
|
||||
read_raw(array, mem_datatype);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::write(const T& buffer) {
|
||||
const DataSpace& mem_space = getMemSpace();
|
||||
auto dims = mem_space.getDimensions();
|
||||
|
||||
if (mem_space.getElementCount() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto file_datatype = getDataType();
|
||||
|
||||
const details::BufferInfo<T> buffer_info(
|
||||
file_datatype,
|
||||
[this]() -> std::string { return this->getName(); },
|
||||
details::BufferInfo<T>::Operation::write);
|
||||
|
||||
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
|
||||
std::ostringstream ss;
|
||||
ss << "Impossible to write attribute of dimensions " << mem_space.getNumberDimensions()
|
||||
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
|
||||
<< buffer_info.getMaxRank() << "(max)";
|
||||
throw DataSpaceException(ss.str());
|
||||
}
|
||||
auto w = details::data_converter::serialize<T>(buffer, dims, file_datatype);
|
||||
write_raw(w.getPointer(), buffer_info.data_type);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::write_raw(const T* buffer, const DataType& mem_datatype) {
|
||||
detail::h5a_write(getId(), mem_datatype.getId(), buffer);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void Attribute::write_raw(const T* buffer) {
|
||||
using element_type = typename details::inspector<T>::base_type;
|
||||
const auto& mem_datatype = create_and_check_datatype<element_type>();
|
||||
|
||||
write_raw(buffer, mem_datatype);
|
||||
}
|
||||
|
||||
inline Attribute Attribute::squeezeMemSpace(const std::vector<size_t>& axes) const {
|
||||
auto mem_dims = this->getMemSpace().getDimensions();
|
||||
auto squeezed_dims = detail::squeeze(mem_dims, axes);
|
||||
|
||||
auto attr = *this;
|
||||
attr._mem_space = DataSpace(squeezed_dims);
|
||||
return attr;
|
||||
}
|
||||
|
||||
inline Attribute Attribute::reshapeMemSpace(const std::vector<size_t>& new_dims) const {
|
||||
detail::assert_compatible_spaces(this->getMemSpace(), new_dims);
|
||||
|
||||
auto attr = *this;
|
||||
attr._mem_space = DataSpace(new_dims);
|
||||
return attr;
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
426
include/highfive/bits/H5Converter_misc.hpp
Normal file
426
include/highfive/bits/H5Converter_misc.hpp
Normal file
@ -0,0 +1,426 @@
|
||||
/*
|
||||
* 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 <type_traits>
|
||||
|
||||
#include "H5Inspector_misc.hpp"
|
||||
#include "../H5DataType.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <class T>
|
||||
struct is_std_string {
|
||||
static constexpr bool value =
|
||||
std::is_same<typename inspector<T>::base_type, std::string>::value;
|
||||
};
|
||||
|
||||
template <class T, class V = void>
|
||||
struct enable_shallow_copy
|
||||
: public std::enable_if<!is_std_string<T>::value && inspector<T>::is_trivially_copyable, V> {};
|
||||
|
||||
template <class T, class V = void>
|
||||
struct enable_deep_copy
|
||||
: public std::enable_if<!is_std_string<T>::value && !inspector<T>::is_trivially_copyable, V> {};
|
||||
|
||||
template <class T, class V = void>
|
||||
struct enable_string_copy: public std::enable_if<is_std_string<T>::value, V> {};
|
||||
|
||||
|
||||
template <typename T, bool IsReadOnly>
|
||||
struct ShallowCopyBuffer {
|
||||
using type = unqualified_t<T>;
|
||||
using hdf5_type =
|
||||
typename std::conditional<IsReadOnly,
|
||||
typename std::add_const<typename inspector<T>::hdf5_type>::type,
|
||||
typename inspector<T>::hdf5_type>::type;
|
||||
|
||||
ShallowCopyBuffer() = delete;
|
||||
|
||||
explicit ShallowCopyBuffer(typename std::conditional<IsReadOnly, const T&, T&>::type val)
|
||||
: ptr(inspector<T>::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 <class T>
|
||||
struct DeepCopyBuffer {
|
||||
using type = unqualified_t<T>;
|
||||
using hdf5_type = typename inspector<type>::hdf5_type;
|
||||
|
||||
explicit DeepCopyBuffer(const std::vector<size_t>& _dims)
|
||||
: buffer(compute_total_size(_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<type>::unserialize(buffer.data(), dims, val);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<hdf5_type> buffer;
|
||||
std::vector<size_t> dims;
|
||||
};
|
||||
|
||||
enum class BufferMode { Read, Write };
|
||||
|
||||
|
||||
///
|
||||
/// \brief String length in bytes excluding the `\0`.
|
||||
///
|
||||
inline size_t char_buffer_length(char const* const str, size_t max_string_size) {
|
||||
for (size_t i = 0; i < max_string_size; ++i) {
|
||||
if (str[i] == '\0') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return max_string_size;
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
/// \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 <typename T, BufferMode buffer_mode>
|
||||
struct StringBuffer {
|
||||
using type = unqualified_t<T>;
|
||||
using hdf5_type = typename inspector<type>::hdf5_type;
|
||||
|
||||
class StringView {
|
||||
public:
|
||||
StringView(StringBuffer<T, buffer_mode>& _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 pad) {
|
||||
if (buffer.isVariableLengthString()) {
|
||||
if (pad == 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_max_length) {
|
||||
throw std::invalid_argument("String length too big.");
|
||||
}
|
||||
|
||||
memcpy(&buffer.fixed_length_buffer[i * buffer.string_size], data, length);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
StringBuffer<T, buffer_mode>& buffer;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
|
||||
class StringConstView {
|
||||
public:
|
||||
StringConstView(const StringBuffer<T, buffer_mode>& _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_length(data(), buffer.string_size);
|
||||
} else {
|
||||
return buffer.string_max_length;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const StringBuffer<T, buffer_mode>& buffer;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(StringBuffer<T, buffer_mode>& _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<T, buffer_mode>& buffer;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
StringBuffer(std::vector<size_t> _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_max_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<type>::unserialize(begin(), dims, val);
|
||||
}
|
||||
|
||||
private:
|
||||
StringType file_datatype;
|
||||
StringPadding padding;
|
||||
// Size of buffer required to store the string.
|
||||
// Meaningful for fixed length strings only.
|
||||
size_t string_size;
|
||||
// Maximum length of string.
|
||||
size_t string_max_length;
|
||||
std::vector<size_t> dims;
|
||||
|
||||
std::vector<char> fixed_length_buffer;
|
||||
std::vector<std::string> variable_length_buffer;
|
||||
std::vector<
|
||||
typename std::conditional<buffer_mode == BufferMode::Write, const char, char>::type*>
|
||||
variable_length_pointers;
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct Writer;
|
||||
|
||||
template <typename T>
|
||||
struct Writer<T, typename enable_shallow_copy<T>::type>: public ShallowCopyBuffer<T, true> {
|
||||
private:
|
||||
using super = ShallowCopyBuffer<T, true>;
|
||||
|
||||
public:
|
||||
explicit Writer(const T& val,
|
||||
const std::vector<size_t>& /* dims */,
|
||||
const DataType& /* file_datatype */)
|
||||
: super(val) {};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Writer<T, typename enable_deep_copy<T>::type>: public DeepCopyBuffer<T> {
|
||||
explicit Writer(const T& val,
|
||||
const std::vector<size_t>& _dims,
|
||||
const DataType& /* file_datatype */)
|
||||
: DeepCopyBuffer<T>(_dims) {
|
||||
inspector<T>::serialize(val, _dims, this->begin());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Writer<T, typename enable_string_copy<T>::type>: public StringBuffer<T, BufferMode::Write> {
|
||||
explicit Writer(const T& val, const std::vector<size_t>& _dims, const DataType& _file_datatype)
|
||||
: StringBuffer<T, BufferMode::Write>(_dims, _file_datatype) {
|
||||
inspector<T>::serialize(val, _dims, this->begin());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct Reader;
|
||||
|
||||
template <typename T>
|
||||
struct Reader<T, typename enable_shallow_copy<T>::type>: public ShallowCopyBuffer<T, false> {
|
||||
private:
|
||||
using super = ShallowCopyBuffer<T, false>;
|
||||
using type = typename super::type;
|
||||
|
||||
public:
|
||||
Reader(const std::vector<size_t>&, type& val, const DataType& /* file_datatype */)
|
||||
: super(val) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct Reader<T, typename enable_deep_copy<T>::type>: public DeepCopyBuffer<T> {
|
||||
private:
|
||||
using super = DeepCopyBuffer<T>;
|
||||
using type = typename super::type;
|
||||
|
||||
public:
|
||||
Reader(const std::vector<size_t>& _dims, type&, const DataType& /* file_datatype */)
|
||||
: super(_dims) {}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct Reader<T, typename enable_string_copy<T>::type>: public StringBuffer<T, BufferMode::Write> {
|
||||
public:
|
||||
explicit Reader(const std::vector<size_t>& _dims,
|
||||
const T& /* val */,
|
||||
const DataType& _file_datatype)
|
||||
: StringBuffer<T, BufferMode::Write>(_dims, _file_datatype) {}
|
||||
};
|
||||
|
||||
struct data_converter {
|
||||
template <typename T>
|
||||
static Writer<T> serialize(const typename inspector<T>::type& val,
|
||||
const std::vector<size_t>& dims,
|
||||
const DataType& file_datatype) {
|
||||
return Writer<T>(val, dims, file_datatype);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static Reader<T> get_reader(const std::vector<size_t>& dims,
|
||||
T& val,
|
||||
const DataType& file_datatype) {
|
||||
inspector<T>::prepare(val, dims);
|
||||
return Reader<T>(dims, val, file_datatype);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
62
include/highfive/bits/H5DataSet_misc.hpp
Normal file
62
include/highfive/bits/H5DataSet_misc.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <algorithm>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
#include "h5d_wrapper.hpp"
|
||||
#include "H5Utils.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline uint64_t DataSet::getStorageSize() const {
|
||||
if (!this->isValid()) {
|
||||
throw DataSetException("Invalid call to `DataSet::getStorageSize` for invalid object");
|
||||
}
|
||||
|
||||
return detail::h5d_get_storage_size(_hid);
|
||||
}
|
||||
|
||||
inline DataType DataSet::getDataType() const {
|
||||
return DataType(detail::h5d_get_type(_hid));
|
||||
}
|
||||
|
||||
inline DataSpace DataSet::getSpace() const {
|
||||
DataSpace space;
|
||||
space._hid = detail::h5d_get_space(_hid);
|
||||
return space;
|
||||
}
|
||||
|
||||
inline DataSpace DataSet::getMemSpace() const {
|
||||
return getSpace();
|
||||
}
|
||||
|
||||
inline uint64_t DataSet::getOffset() const {
|
||||
return static_cast<uint64_t>(detail::h5d_get_offset(_hid));
|
||||
}
|
||||
|
||||
inline void DataSet::resize(const std::vector<size_t>& dims) {
|
||||
const size_t numDimensions = getSpace().getDimensions().size();
|
||||
if (dims.size() != numDimensions) {
|
||||
HDF5ErrMapper::ToException<DataSetException>("Invalid dataspace dimensions, got " +
|
||||
std::to_string(dims.size()) + " expected " +
|
||||
std::to_string(numDimensions));
|
||||
}
|
||||
|
||||
std::vector<hsize_t> real_dims(dims.begin(), dims.end());
|
||||
detail::h5d_set_extent(getId(), real_dims.data());
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
474
include/highfive/bits/H5DataType_misc.hpp
Normal file
474
include/highfive/bits/H5DataType_misc.hpp
Normal file
@ -0,0 +1,474 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
#include <complex>
|
||||
#include <cstring>
|
||||
#if HIGHFIVE_CXX_STD >= 17
|
||||
#include <cstddef>
|
||||
#endif
|
||||
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
#include "H5Inspector_misc.hpp"
|
||||
#include "h5t_wrapper.hpp"
|
||||
#include "h5i_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace { // unnamed
|
||||
inline DataTypeClass convert_type_class(const H5T_class_t& tclass);
|
||||
inline std::string type_class_string(DataTypeClass);
|
||||
inline hid_t create_string(std::size_t length);
|
||||
} // namespace
|
||||
|
||||
inline bool DataType::empty() const noexcept {
|
||||
return _hid == H5I_INVALID_HID;
|
||||
}
|
||||
|
||||
inline DataTypeClass DataType::getClass() const {
|
||||
return convert_type_class(detail::h5t_get_class(_hid));
|
||||
}
|
||||
|
||||
inline size_t DataType::getSize() const {
|
||||
return detail::h5t_get_size(_hid);
|
||||
}
|
||||
|
||||
inline bool DataType::operator==(const DataType& other) const {
|
||||
return detail::h5t_equal(_hid, other._hid) > 0;
|
||||
}
|
||||
|
||||
inline bool DataType::operator!=(const DataType& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
inline bool DataType::isVariableStr() const {
|
||||
return detail::h5t_is_variable_str(_hid) > 0;
|
||||
}
|
||||
|
||||
inline bool DataType::isFixedLenStr() const {
|
||||
return getClass() == DataTypeClass::String && !isVariableStr();
|
||||
}
|
||||
|
||||
inline bool DataType::isReference() const {
|
||||
return detail::h5t_equal(_hid, H5T_STD_REF_OBJ) > 0;
|
||||
}
|
||||
|
||||
inline StringType DataType::asStringType() const {
|
||||
if (getClass() != DataTypeClass::String) {
|
||||
throw DataTypeException("Invalid conversion to StringType.");
|
||||
}
|
||||
|
||||
if (isValid()) {
|
||||
detail::h5i_inc_ref(_hid);
|
||||
}
|
||||
|
||||
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<char>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_CHAR);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<signed char>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_SCHAR);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<unsigned char>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_UCHAR);
|
||||
}
|
||||
|
||||
// short mapping
|
||||
template <>
|
||||
inline AtomicType<short>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_SHORT);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<unsigned short>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_USHORT);
|
||||
}
|
||||
|
||||
// integer mapping
|
||||
template <>
|
||||
inline AtomicType<int>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_INT);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<unsigned>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_UINT);
|
||||
}
|
||||
|
||||
// long mapping
|
||||
template <>
|
||||
inline AtomicType<long>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_LONG);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<unsigned long>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_ULONG);
|
||||
}
|
||||
|
||||
// long long mapping
|
||||
template <>
|
||||
inline AtomicType<long long>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_LLONG);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<unsigned long long>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_ULLONG);
|
||||
}
|
||||
|
||||
// half-float, float, double and long double mapping
|
||||
template <>
|
||||
inline AtomicType<float>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_FLOAT);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<double>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_DOUBLE);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline AtomicType<long double>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_LDOUBLE);
|
||||
}
|
||||
|
||||
// std string
|
||||
template <>
|
||||
inline AtomicType<std::string>::AtomicType() {
|
||||
_hid = create_string(H5T_VARIABLE);
|
||||
}
|
||||
|
||||
#if HIGHFIVE_CXX_STD >= 17
|
||||
// std byte
|
||||
template <>
|
||||
inline AtomicType<std::byte>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_B8);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Fixed-Length strings
|
||||
// require class specialization templated for the char length
|
||||
template <size_t StrLen>
|
||||
class AtomicType<char[StrLen]>: public DataType {
|
||||
public:
|
||||
inline AtomicType()
|
||||
: DataType(create_string(StrLen)) {}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class AtomicType<std::complex<T>>: public DataType {
|
||||
public:
|
||||
inline AtomicType()
|
||||
: DataType(
|
||||
CompoundType({{"r", create_datatype<T>(), 0}, {"i", create_datatype<T>(), sizeof(T)}},
|
||||
sizeof(std::complex<T>))) {
|
||||
static_assert(std::is_arithmetic<T>::value,
|
||||
"std::complex accepts only floating point and integral numbers.");
|
||||
}
|
||||
};
|
||||
|
||||
// For boolean we act as h5py
|
||||
inline EnumType<details::Boolean> create_enum_boolean() {
|
||||
return {{"FALSE", details::Boolean::HighFiveFalse}, {"TRUE", details::Boolean::HighFiveTrue}};
|
||||
}
|
||||
|
||||
// Other cases not supported. Fail early with a user message
|
||||
template <typename T>
|
||||
AtomicType<T>::AtomicType() {
|
||||
static_assert(
|
||||
true,
|
||||
"Missing specialization of AtomicType<T>. Therefore, type T is not supported by HighFive.");
|
||||
}
|
||||
|
||||
|
||||
// Internal
|
||||
// Reference mapping
|
||||
template <>
|
||||
inline AtomicType<Reference>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_STD_REF_OBJ);
|
||||
}
|
||||
|
||||
inline size_t find_first_atomic_member_size(hid_t hid) {
|
||||
// Recursive exit condition
|
||||
if (detail::h5t_get_class(hid) == H5T_COMPOUND) {
|
||||
auto number_of_members = detail::h5t_get_nmembers(hid);
|
||||
if (number_of_members == -1) {
|
||||
throw DataTypeException("Cannot get members of CompoundType with hid: " +
|
||||
std::to_string(hid));
|
||||
}
|
||||
if (number_of_members == 0) {
|
||||
throw DataTypeException("No members defined for CompoundType with hid: " +
|
||||
std::to_string(hid));
|
||||
}
|
||||
|
||||
auto member_type = detail::h5t_get_member_type(hid, 0);
|
||||
auto size = find_first_atomic_member_size(member_type);
|
||||
detail::h5t_close(member_type);
|
||||
return size;
|
||||
} else if (detail::h5t_get_class(hid) == H5T_STRING) {
|
||||
return 1;
|
||||
}
|
||||
return detail::h5t_get_size(hid);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// Calculate the padding required to align an element of a struct
|
||||
// For padding see explanation here: https://en.cppreference.com/w/cpp/language/object#Alignment
|
||||
// It is to compute padding following last element inserted inside a struct
|
||||
// 1) We want to push back an element padded to the structure
|
||||
// 'current_size' is the size of the structure before adding the new element.
|
||||
// 'member_size' the size of the element we want to add.
|
||||
// 2) We want to compute the final padding for the global structure
|
||||
// 'current_size' is the size of the whole structure without final padding
|
||||
// 'member_size' is the maximum size of all element of the struct
|
||||
//
|
||||
// The basic formula is only to know how much we need to add to 'current_size' to fit
|
||||
// 'member_size'.
|
||||
// And at the end, we do another computation because the end padding, should fit the biggest
|
||||
// element of the struct.
|
||||
//
|
||||
// As we are with `size_t` element, we need to compute everything inside R+
|
||||
inline size_t struct_padding(size_t current_size, size_t member_size) {
|
||||
if (member_size == 0) {
|
||||
throw DataTypeException("Unexpected `member_size == 0`.");
|
||||
}
|
||||
|
||||
return member_size >= current_size
|
||||
? (member_size - current_size) % member_size
|
||||
: ((member_size - ((current_size - member_size) % member_size))) % member_size;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline void CompoundType::create(size_t size) {
|
||||
if (size == 0) {
|
||||
size_t current_size = 0, max_atomic_size = 0;
|
||||
|
||||
// Do a first pass to find the total size of the compound datatype
|
||||
for (auto& member: members) {
|
||||
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: " +
|
||||
std::to_string(member.base_type.getId()));
|
||||
}
|
||||
|
||||
size_t first_atomic_size = find_first_atomic_member_size(member.base_type.getId());
|
||||
|
||||
// Set the offset of this member within the struct according to the
|
||||
// standard alignment rules. The c++ standard specifies that:
|
||||
// > objects have an alignment requirement of which their size is a multiple
|
||||
member.offset = current_size + detail::struct_padding(current_size, first_atomic_size);
|
||||
|
||||
// Set the current size to the end of the new member
|
||||
current_size = member.offset + member_size;
|
||||
|
||||
// Keep track of the highest atomic member size because it's needed
|
||||
// for the padding of the complete compound type.
|
||||
max_atomic_size = std::max(max_atomic_size, first_atomic_size);
|
||||
}
|
||||
|
||||
size = current_size + detail::struct_padding(current_size, max_atomic_size);
|
||||
}
|
||||
|
||||
// Create the HDF5 type
|
||||
_hid = detail::h5t_create(H5T_COMPOUND, size);
|
||||
|
||||
// Loop over all the members and insert them into the datatype
|
||||
for (const auto& member: members) {
|
||||
detail::h5t_insert(_hid, member.name.c_str(), member.offset, member.base_type.getId());
|
||||
}
|
||||
}
|
||||
|
||||
inline void CompoundType::commit(const Object& object, const std::string& name) const {
|
||||
detail::h5t_commit2(
|
||||
object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void EnumType<T>::create() {
|
||||
// Create the HDF5 type
|
||||
_hid = detail::h5t_enum_create(AtomicType<typename std::underlying_type<T>::type>{}.getId());
|
||||
|
||||
// Loop over all the members and insert them into the datatype
|
||||
for (const auto& member: members) {
|
||||
detail::h5t_enum_insert(_hid, member.name.c_str(), &(member.value));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void EnumType<T>::commit(const Object& object, const std::string& name) const {
|
||||
detail::h5t_commit2(
|
||||
object.getId(), name.c_str(), getId(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline hid_t create_string(size_t length) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
inline DataTypeClass convert_type_class(const H5T_class_t& tclass) {
|
||||
switch (tclass) {
|
||||
case H5T_TIME:
|
||||
return DataTypeClass::Time;
|
||||
case H5T_INTEGER:
|
||||
return DataTypeClass::Integer;
|
||||
case H5T_FLOAT:
|
||||
return DataTypeClass::Float;
|
||||
case H5T_STRING:
|
||||
return DataTypeClass::String;
|
||||
case H5T_BITFIELD:
|
||||
return DataTypeClass::BitField;
|
||||
case H5T_OPAQUE:
|
||||
return DataTypeClass::Opaque;
|
||||
case H5T_COMPOUND:
|
||||
return DataTypeClass::Compound;
|
||||
case H5T_REFERENCE:
|
||||
return DataTypeClass::Reference;
|
||||
case H5T_ENUM:
|
||||
return DataTypeClass::Enum;
|
||||
case H5T_VLEN:
|
||||
return DataTypeClass::VarLen;
|
||||
case H5T_ARRAY:
|
||||
return DataTypeClass::Array;
|
||||
case H5T_NO_CLASS:
|
||||
case H5T_NCLASSES:
|
||||
default:
|
||||
return DataTypeClass::Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline std::string type_class_string(DataTypeClass tclass) {
|
||||
switch (tclass) {
|
||||
case DataTypeClass::Time:
|
||||
return "Time";
|
||||
case DataTypeClass::Integer:
|
||||
return "Integer";
|
||||
case DataTypeClass::Float:
|
||||
return "Float";
|
||||
case DataTypeClass::String:
|
||||
return "String";
|
||||
case DataTypeClass::BitField:
|
||||
return "BitField";
|
||||
case DataTypeClass::Opaque:
|
||||
return "Opaque";
|
||||
case DataTypeClass::Compound:
|
||||
return "Compound";
|
||||
case DataTypeClass::Reference:
|
||||
return "Reference";
|
||||
case DataTypeClass::Enum:
|
||||
return "Enum";
|
||||
case DataTypeClass::VarLen:
|
||||
return "Varlen";
|
||||
case DataTypeClass::Array:
|
||||
return "Array";
|
||||
default:
|
||||
return "(Invalid)";
|
||||
}
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
||||
|
||||
/// \brief Create a DataType instance representing type T
|
||||
template <typename T>
|
||||
inline DataType create_datatype() {
|
||||
return AtomicType<T>();
|
||||
}
|
||||
|
||||
|
||||
/// \brief Create a DataType instance representing type T and perform a sanity check on its size
|
||||
template <typename T>
|
||||
inline DataType create_and_check_datatype() {
|
||||
DataType t = create_datatype<T>();
|
||||
if (t.empty()) {
|
||||
throw DataTypeException("Type given to create_and_check_datatype is not valid");
|
||||
}
|
||||
|
||||
// Skip check if the base type is a variable length string
|
||||
if (t.isVariableStr()) {
|
||||
return t;
|
||||
}
|
||||
|
||||
// Check that the size of the template type matches the size that HDF5 is
|
||||
// expecting.
|
||||
if (t.isReference() || t.isFixedLenStr()) {
|
||||
return t;
|
||||
}
|
||||
if (sizeof(T) != t.getSize()) {
|
||||
std::ostringstream ss;
|
||||
ss << "Size of array type " << sizeof(T) << " != that of memory datatype " << t.getSize()
|
||||
<< std::endl;
|
||||
throw DataTypeException(ss.str());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
HIGHFIVE_REGISTER_TYPE(HighFive::details::Boolean, HighFive::create_enum_boolean)
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <>
|
||||
inline DataType create_datatype<bool>() {
|
||||
return create_datatype<HighFive::details::Boolean>();
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
146
include/highfive/bits/H5Dataspace_misc.hpp
Normal file
146
include/highfive/bits/H5Dataspace_misc.hpp
Normal file
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <array>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
|
||||
#include <H5Spublic.h>
|
||||
|
||||
#include "H5Utils.hpp"
|
||||
#include "H5Converter_misc.hpp"
|
||||
#include "h5s_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace detail {
|
||||
inline DataSpace make_data_space(hid_t hid) {
|
||||
return DataSpace::fromId(hid);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
inline DataSpace::DataSpace(const std::vector<size_t>& dims)
|
||||
: DataSpace(dims.begin(), dims.end()) {}
|
||||
|
||||
template <size_t N>
|
||||
inline DataSpace::DataSpace(const std::array<size_t, N>& dims)
|
||||
: DataSpace(dims.begin(), dims.end()) {}
|
||||
|
||||
inline DataSpace::DataSpace(const std::initializer_list<size_t>& items)
|
||||
: DataSpace(std::vector<size_t>(items)) {}
|
||||
|
||||
template <typename... Args>
|
||||
inline DataSpace::DataSpace(size_t dim1, Args... dims)
|
||||
: DataSpace(std::vector<size_t>{dim1, static_cast<size_t>(dims)...}) {}
|
||||
|
||||
template <class IT, typename>
|
||||
inline DataSpace::DataSpace(const IT begin, const IT end) {
|
||||
std::vector<hsize_t> real_dims(begin, end);
|
||||
|
||||
_hid = detail::h5s_create_simple(int(real_dims.size()), real_dims.data(), nullptr);
|
||||
}
|
||||
|
||||
inline DataSpace DataSpace::Scalar() {
|
||||
return DataSpace(DataSpace::dataspace_scalar);
|
||||
}
|
||||
|
||||
inline DataSpace DataSpace::Null() {
|
||||
return DataSpace(DataSpace::dataspace_null);
|
||||
}
|
||||
|
||||
inline DataSpace::DataSpace(const std::vector<size_t>& dims, const std::vector<size_t>& maxdims) {
|
||||
if (dims.size() != maxdims.size()) {
|
||||
throw DataSpaceException("dims and maxdims must be the same length.");
|
||||
}
|
||||
|
||||
std::vector<hsize_t> real_dims(dims.begin(), dims.end());
|
||||
std::vector<hsize_t> real_maxdims(maxdims.begin(), maxdims.end());
|
||||
|
||||
// Replace unlimited flag with actual HDF one
|
||||
std::replace(real_maxdims.begin(),
|
||||
real_maxdims.end(),
|
||||
static_cast<hsize_t>(DataSpace::UNLIMITED),
|
||||
H5S_UNLIMITED);
|
||||
|
||||
_hid = detail::h5s_create_simple(int(dims.size()), real_dims.data(), real_maxdims.data());
|
||||
}
|
||||
|
||||
inline DataSpace::DataSpace(DataSpace::DataspaceType space_type) {
|
||||
auto to_hdf5 = [](auto _space_type) -> H5S_class_t {
|
||||
switch (_space_type) {
|
||||
case DataSpace::dataspace_scalar:
|
||||
return H5S_SCALAR;
|
||||
case DataSpace::dataspace_null:
|
||||
return H5S_NULL;
|
||||
default:
|
||||
throw DataSpaceException(
|
||||
"Invalid dataspace type: should be "
|
||||
"dataspace_scalar or dataspace_null");
|
||||
}
|
||||
};
|
||||
|
||||
_hid = detail::h5s_create(to_hdf5(space_type));
|
||||
}
|
||||
|
||||
inline DataSpace DataSpace::clone() const {
|
||||
DataSpace res;
|
||||
res._hid = detail::h5s_copy(_hid);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline size_t DataSpace::getNumberDimensions() const {
|
||||
return static_cast<size_t>(detail::h5s_get_simple_extent_ndims(_hid));
|
||||
}
|
||||
|
||||
inline std::vector<size_t> DataSpace::getDimensions() const {
|
||||
std::vector<hsize_t> dims(getNumberDimensions());
|
||||
if (!dims.empty()) {
|
||||
detail::h5s_get_simple_extent_dims(_hid, dims.data(), nullptr);
|
||||
}
|
||||
return details::to_vector_size_t(std::move(dims));
|
||||
}
|
||||
|
||||
inline size_t DataSpace::getElementCount() const {
|
||||
return static_cast<size_t>(detail::h5s_get_simple_extent_npoints(_hid));
|
||||
}
|
||||
|
||||
inline std::vector<size_t> DataSpace::getMaxDimensions() const {
|
||||
std::vector<hsize_t> maxdims(getNumberDimensions());
|
||||
detail::h5s_get_simple_extent_dims(_hid, nullptr, maxdims.data());
|
||||
|
||||
std::replace(maxdims.begin(),
|
||||
maxdims.end(),
|
||||
H5S_UNLIMITED,
|
||||
static_cast<hsize_t>(DataSpace::UNLIMITED));
|
||||
return details::to_vector_size_t(maxdims);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline DataSpace DataSpace::From(const T& value) {
|
||||
auto dims = details::inspector<T>::getDimensions(value);
|
||||
return DataSpace(dims);
|
||||
}
|
||||
|
||||
template <std::size_t N, std::size_t Width>
|
||||
inline DataSpace DataSpace::FromCharArrayStrings(const char (&)[N][Width]) {
|
||||
return DataSpace(N);
|
||||
}
|
||||
|
||||
namespace details {
|
||||
|
||||
inline bool checkDimensions(const DataSpace& mem_space,
|
||||
size_t min_dim_requested,
|
||||
size_t max_dim_requested) {
|
||||
return checkDimensions(mem_space.getDimensions(), min_dim_requested, max_dim_requested);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
67
include/highfive/bits/H5Exception_misc.hpp
Normal file
67
include/highfive/bits/H5Exception_misc.hpp
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
#include "h5_wrapper.hpp"
|
||||
#include "h5e_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
struct HDF5ErrMapper {
|
||||
template <typename ExceptionType>
|
||||
static inline herr_t stackWalk(unsigned /* n */,
|
||||
const H5E_error2_t* err_desc,
|
||||
void* client_data) {
|
||||
auto** e_iter = static_cast<ExceptionType**>(client_data);
|
||||
|
||||
const char* major_err = detail::nothrow::h5e_get_major(err_desc->maj_num);
|
||||
const char* minor_err = detail::nothrow::h5e_get_minor(err_desc->min_num);
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << '(' << major_err << ") " << minor_err;
|
||||
|
||||
detail::nothrow::h5_free_memory((void*) major_err);
|
||||
detail::nothrow::h5_free_memory((void*) minor_err);
|
||||
|
||||
auto* e = new ExceptionType(oss.str());
|
||||
e->_err_major = err_desc->maj_num;
|
||||
e->_err_minor = err_desc->min_num;
|
||||
(*e_iter)->_next.reset(e);
|
||||
*e_iter = e;
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename ExceptionType>
|
||||
[[noreturn]] static inline void ToException(const std::string& prefix_msg) {
|
||||
hid_t err_stack = H5Eget_current_stack();
|
||||
if (err_stack >= 0) {
|
||||
ExceptionType e("");
|
||||
ExceptionType* e_iter = &e;
|
||||
|
||||
detail::nothrow::h5e_walk2(err_stack,
|
||||
H5E_WALK_UPWARD,
|
||||
&HDF5ErrMapper::stackWalk<ExceptionType>,
|
||||
(void*) &e_iter);
|
||||
detail::nothrow::h5e_clear2(err_stack);
|
||||
|
||||
const char* next_err_msg = (e.nextException() != NULL) ? (e.nextException()->what())
|
||||
: ("");
|
||||
|
||||
e.setErrorMsg(prefix_msg + " " + next_err_msg);
|
||||
throw e;
|
||||
}
|
||||
// throw generic error, unrecognized error
|
||||
throw ExceptionType(prefix_msg + ": Unknown HDF5 error");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
140
include/highfive/bits/H5File_misc.hpp
Normal file
140
include/highfive/bits/H5File_misc.hpp
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
|
||||
#include <H5Fpublic.h>
|
||||
|
||||
#include "../H5Utility.hpp"
|
||||
#include "H5Utils.hpp"
|
||||
#include "h5f_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace { // unnamed
|
||||
|
||||
// libhdf5 uses a preprocessor trick on their oflags
|
||||
// we can not declare them constant without a mapper
|
||||
inline unsigned convert_open_flag(File::AccessMode openFlags) {
|
||||
unsigned res_open = 0;
|
||||
if (any(openFlags & File::ReadOnly))
|
||||
res_open |= H5F_ACC_RDONLY;
|
||||
if (any(openFlags & File::ReadWrite))
|
||||
res_open |= H5F_ACC_RDWR;
|
||||
if (any(openFlags & File::Create))
|
||||
res_open |= H5F_ACC_CREAT;
|
||||
if (any(openFlags & File::Truncate))
|
||||
res_open |= H5F_ACC_TRUNC;
|
||||
if (any(openFlags & File::Excl))
|
||||
res_open |= H5F_ACC_EXCL;
|
||||
return res_open;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
inline File::File(const std::string& filename,
|
||||
AccessMode openFlags,
|
||||
const FileAccessProps& fileAccessProps)
|
||||
: File(filename, openFlags, FileCreateProps::Default(), fileAccessProps) {}
|
||||
|
||||
|
||||
inline File::File(const std::string& filename,
|
||||
AccessMode access_mode,
|
||||
const FileCreateProps& fileCreateProps,
|
||||
const FileAccessProps& fileAccessProps) {
|
||||
unsigned openFlags = convert_open_flag(access_mode);
|
||||
|
||||
unsigned createMode = openFlags & (H5F_ACC_TRUNC | H5F_ACC_EXCL);
|
||||
unsigned openMode = openFlags & (H5F_ACC_RDWR | H5F_ACC_RDONLY);
|
||||
bool mustCreate = createMode > 0;
|
||||
bool openOrCreate = (openFlags & H5F_ACC_CREAT) > 0;
|
||||
|
||||
// open is default. It's skipped only if flags require creation
|
||||
// If open fails it will try create() if H5F_ACC_CREAT is set
|
||||
if (!mustCreate) {
|
||||
// Silence open errors if create is allowed
|
||||
std::unique_ptr<SilenceHDF5> silencer;
|
||||
if (openOrCreate) {
|
||||
silencer = std::make_unique<SilenceHDF5>();
|
||||
}
|
||||
|
||||
_hid = detail::nothrow::h5f_open(filename.c_str(), openMode, fileAccessProps.getId());
|
||||
|
||||
if (isValid()) {
|
||||
return; // Done
|
||||
}
|
||||
|
||||
if (openOrCreate) {
|
||||
// Will attempt to create ensuring wont clobber any file
|
||||
createMode = H5F_ACC_EXCL;
|
||||
} else {
|
||||
HDF5ErrMapper::ToException<FileException>(
|
||||
std::string("Unable to open file " + filename));
|
||||
}
|
||||
}
|
||||
|
||||
auto fcpl = fileCreateProps.getId();
|
||||
auto fapl = fileAccessProps.getId();
|
||||
_hid = detail::h5f_create(filename.c_str(), createMode, fcpl, fapl);
|
||||
}
|
||||
|
||||
inline const std::string& File::getName() const {
|
||||
if (_filename.empty()) {
|
||||
_filename = details::get_name([this](char* buffer, size_t length) {
|
||||
return detail::h5f_get_name(getId(), buffer, length);
|
||||
});
|
||||
}
|
||||
return _filename;
|
||||
}
|
||||
|
||||
inline hsize_t File::getMetadataBlockSize() const {
|
||||
auto fapl = getAccessPropertyList();
|
||||
return MetadataBlockSize(fapl).getSize();
|
||||
}
|
||||
|
||||
inline std::pair<H5F_libver_t, H5F_libver_t> File::getVersionBounds() const {
|
||||
auto fapl = getAccessPropertyList();
|
||||
auto fileVer = FileVersionBounds(fapl);
|
||||
return fileVer.getVersion();
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 1)
|
||||
inline H5F_fspace_strategy_t File::getFileSpaceStrategy() const {
|
||||
auto fcpl = getCreatePropertyList();
|
||||
FileSpaceStrategy spaceStrategy(fcpl);
|
||||
return spaceStrategy.getStrategy();
|
||||
}
|
||||
|
||||
inline hsize_t File::getFileSpacePageSize() const {
|
||||
auto fcpl = getCreatePropertyList();
|
||||
|
||||
if (getFileSpaceStrategy() != H5F_FSPACE_STRATEGY_PAGE) {
|
||||
HDF5ErrMapper::ToException<FileException>(
|
||||
std::string("Cannot obtain page size as paged allocation is not used."));
|
||||
}
|
||||
|
||||
return FileSpacePageSize(fcpl).getPageSize();
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void File::flush() {
|
||||
detail::h5f_flush(_hid, H5F_SCOPE_GLOBAL);
|
||||
}
|
||||
|
||||
inline size_t File::getFileSize() const {
|
||||
hsize_t sizeValue = 0;
|
||||
detail::h5f_get_filesize(_hid, &sizeValue);
|
||||
return static_cast<size_t>(sizeValue);
|
||||
}
|
||||
|
||||
inline size_t File::getFreeSpace() const {
|
||||
return static_cast<size_t>(detail::h5f_get_freespace(_hid));
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
10
include/highfive/bits/H5Friends.hpp
Normal file
10
include/highfive/bits/H5Friends.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef HIGHFIVE_HAS_FRIEND_DECLARATIONS
|
||||
#ifdef _MSC_VER
|
||||
// This prevents a compiler bug on certain versions of MSVC.
|
||||
// Known to fail: Toolset 141.
|
||||
// See `CMakeLists.txt` for more information.
|
||||
#define HIGHFIVE_HAS_FRIEND_DECLARATIONS 1
|
||||
#endif
|
||||
#endif
|
||||
19
include/highfive/bits/H5Inspector_decl.hpp
Normal file
19
include/highfive/bits/H5Inspector_decl.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "compute_total_size.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <typename T>
|
||||
using unqualified_t = typename std::remove_const<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename T>
|
||||
struct type_helper;
|
||||
|
||||
template <typename T>
|
||||
struct inspector;
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
524
include/highfive/bits/H5Inspector_misc.hpp
Normal file
524
include/highfive/bits/H5Inspector_misc.hpp
Normal file
@ -0,0 +1,524 @@
|
||||
/*
|
||||
* 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 <type_traits>
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <numeric>
|
||||
|
||||
#include "../H5Reference.hpp"
|
||||
|
||||
#include "string_padding.hpp"
|
||||
|
||||
#include "H5Inspector_decl.hpp"
|
||||
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
inline bool checkDimensions(const std::vector<size_t>& dims,
|
||||
size_t min_dim_requested,
|
||||
size_t max_dim_requested) {
|
||||
if (min_dim_requested <= dims.size() && dims.size() <= max_dim_requested) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Scalar values still support broadcasting
|
||||
// into arrays with one element.
|
||||
size_t n_elements = compute_total_size(dims);
|
||||
return n_elements == 1 && min_dim_requested == 0;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
|
||||
/*****
|
||||
inspector<T> {
|
||||
using type = T
|
||||
// base_type is the base type inside c++ (e.g. std::vector<int> => int)
|
||||
using base_type
|
||||
// hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector<std::string> => const char*)
|
||||
using hdf5_type
|
||||
|
||||
// Is the inner type trivially copyable for optimisation
|
||||
// If this value is true: data() is mandatory
|
||||
// If this value is false: serialize, unserialize are mandatory
|
||||
static constexpr bool is_trivially_copyable
|
||||
|
||||
// Is this type trivially nestable, i.e. is type[n] a contiguous
|
||||
// array of `base_type[N]`?
|
||||
static constexpr bool is_trivially_nestable
|
||||
|
||||
// Reading:
|
||||
// Allocate the value following dims (should be recursive)
|
||||
static void prepare(type& val, const std::vector<std::size_t> 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<size_t>&i, type& val)
|
||||
|
||||
|
||||
// Writing:
|
||||
// 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, const std::vector<size_t>& dims, hdf5_type* out)
|
||||
// Return an array of dimensions of the space needed for writing val
|
||||
static std::vector<size_t> getDimensions(const type& val)
|
||||
}
|
||||
*****/
|
||||
|
||||
|
||||
namespace details {
|
||||
template <typename T>
|
||||
struct type_helper {
|
||||
using type = unqualified_t<T>;
|
||||
using base_type = unqualified_t<T>;
|
||||
using hdf5_type = base_type;
|
||||
|
||||
static constexpr size_t ndim = 0;
|
||||
static constexpr size_t min_ndim = ndim;
|
||||
static constexpr size_t max_ndim = ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
|
||||
static constexpr bool is_trivially_nestable = is_trivially_copyable;
|
||||
|
||||
static size_t getRank(const type& /* val */) {
|
||||
return ndim;
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& /* val */) {
|
||||
return {};
|
||||
}
|
||||
|
||||
static void prepare(type& /* val */, const std::vector<size_t>& /* 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, const std::vector<size_t>& /* dims*/, 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<size_t>& /* dims */,
|
||||
type& val) {
|
||||
static_assert(is_trivially_copyable, "The type is not trivially copyable");
|
||||
val = vec[0];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct inspector: type_helper<T> {};
|
||||
|
||||
enum class Boolean : int8_t {
|
||||
HighFiveFalse = 0,
|
||||
HighFiveTrue = 1,
|
||||
};
|
||||
|
||||
template <>
|
||||
struct inspector<bool>: type_helper<bool> {
|
||||
using base_type = Boolean;
|
||||
using hdf5_type = int8_t;
|
||||
|
||||
static constexpr bool is_trivially_copyable = false;
|
||||
static constexpr bool is_trivially_nestable = 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<size_t>& /* dims */,
|
||||
type& val) {
|
||||
val = vec[0] != 0;
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
||||
*m = val ? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct inspector<std::string>: type_helper<std::string> {
|
||||
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 <class It>
|
||||
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, It m) {
|
||||
(*m).assign(val.data(), val.size(), StringPadding::NullTerminated);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void unserialize(const It& vec, const std::vector<size_t>& /* dims */, type& val) {
|
||||
const auto& view = *vec;
|
||||
val.assign(view.data(), view.length());
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct inspector<Reference>: type_helper<Reference> {
|
||||
using hdf5_type = hobj_ref_t;
|
||||
|
||||
static constexpr bool is_trivially_copyable = false;
|
||||
static constexpr bool is_trivially_nestable = 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, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
||||
hobj_ref_t ref;
|
||||
val.create_ref(&ref);
|
||||
*m = ref;
|
||||
}
|
||||
|
||||
static void unserialize(const hdf5_type* vec,
|
||||
const std::vector<size_t>& /* dims */,
|
||||
type& val) {
|
||||
val = type{vec[0]};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct inspector<std::vector<T>> {
|
||||
using type = std::vector<T>;
|
||||
using value_type = unqualified_t<T>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
if (!val.empty()) {
|
||||
return ndim + inspector<value_type>::getRank(val[0]);
|
||||
} else {
|
||||
return min_ndim;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
auto rank = getRank(val);
|
||||
std::vector<size_t> sizes(rank, 1ul);
|
||||
sizes[0] = val.size();
|
||||
if (!val.empty()) {
|
||||
auto s = inspector<value_type>::getDimensions(val[0]);
|
||||
for (size_t i = 0; i < s.size(); ++i) {
|
||||
sizes[i + ndim] = s[i];
|
||||
}
|
||||
}
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
val.resize(dims[0]);
|
||||
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
||||
for (auto&& e: val) {
|
||||
inspector<value_type>::prepare(e, next_dims);
|
||||
}
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
||||
if (!val.empty()) {
|
||||
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (auto&& e: val) {
|
||||
inspector<value_type>::serialize(e, subdims, m);
|
||||
m += subsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
|
||||
std::vector<size_t> 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<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct inspector<std::vector<bool>> {
|
||||
using type = std::vector<bool>;
|
||||
using value_type = bool;
|
||||
using base_type = Boolean;
|
||||
using hdf5_type = uint8_t;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim;
|
||||
static constexpr size_t max_ndim = ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = false;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& /* val */) {
|
||||
return ndim;
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
std::vector<size_t> sizes{val.size()};
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
if (dims.size() > 1) {
|
||||
throw DataSpaceException("std::vector<bool> is only 1 dimension.");
|
||||
}
|
||||
val.resize(dims[0]);
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& /* val */) {
|
||||
throw DataSpaceException("A std::vector<bool> cannot be read directly.");
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& /* val */) {
|
||||
throw DataSpaceException("A std::vector<bool> cannot be written directly.");
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, 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<size_t>& dims,
|
||||
type& val) {
|
||||
for (size_t i = 0; i < dims[0]; ++i) {
|
||||
val[i] = vec_align[i] != 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct inspector<std::array<T, N>> {
|
||||
using type = std::array<T, N>;
|
||||
using value_type = unqualified_t<T>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = (sizeof(type) == N * sizeof(T)) &&
|
||||
is_trivially_copyable;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
return ndim + inspector<value_type>::getRank(val[0]);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
std::vector<size_t> sizes{N};
|
||||
auto s = inspector<value_type>::getDimensions(val[0]);
|
||||
sizes.insert(sizes.end(), s.begin(), s.end());
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& 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());
|
||||
}
|
||||
|
||||
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
||||
for (auto&& e: val) {
|
||||
inspector<value_type>::prepare(e, next_dims);
|
||||
}
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
return inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
return inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
||||
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (auto& e: val) {
|
||||
inspector<value_type>::serialize(e, subdims, m);
|
||||
m += subsize;
|
||||
}
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void unserialize(const It& vec_align, const std::vector<size_t>& 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<size_t> next_dims(dims.begin() + 1, dims.end());
|
||||
size_t next_size = compute_total_size(next_dims);
|
||||
for (size_t i = 0; i < val.size(); ++i) {
|
||||
inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Cannot be use for reading
|
||||
template <typename T>
|
||||
struct inspector<T*> {
|
||||
using type = T*;
|
||||
using value_type = unqualified_t<T>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
if (val != nullptr) {
|
||||
return ndim + inspector<value_type>::getRank(val[0]);
|
||||
} else {
|
||||
return min_ndim;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<size_t> 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<const hdf5_type*>(val);
|
||||
}
|
||||
|
||||
/* it works because there is only T[][][] currently
|
||||
we will fix it one day */
|
||||
static void serialize(const type& /* val */,
|
||||
const std::vector<size_t>& /* dims*/,
|
||||
hdf5_type* /* m */) {
|
||||
throw DataSpaceException("Not possible to serialize a T*");
|
||||
}
|
||||
};
|
||||
|
||||
// Cannot be use for reading
|
||||
template <typename T, size_t N>
|
||||
struct inspector<T[N]> {
|
||||
using type = T[N];
|
||||
using value_type = unqualified_t<T>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = is_trivially_copyable;
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
if (dims.empty()) {
|
||||
throw DataSpaceException("Invalid 'dims', must be at least 1 dimensional.");
|
||||
}
|
||||
|
||||
if (dims[0] != N) {
|
||||
throw DataSpaceException("Dimensions mismatch.");
|
||||
}
|
||||
|
||||
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
inspector<value_type>::prepare(val[i], next_dims);
|
||||
}
|
||||
}
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
return ndim + inspector<value_type>::getRank(val[0]);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
std::vector<size_t> sizes{N};
|
||||
auto s = inspector<value_type>::getDimensions(val[0]);
|
||||
sizes.insert(sizes.end(), s.begin(), s.end());
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
return inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
return inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
/* it works because there is only T[][][] currently
|
||||
we will fix it one day */
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
||||
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (size_t i = 0; i < N; ++i) {
|
||||
inspector<value_type>::serialize(val[i], subdims, m + i * subsize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
54
include/highfive/bits/H5Iterables_misc.hpp
Normal file
54
include/highfive/bits/H5Iterables_misc.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace details {
|
||||
|
||||
// iterator for H5 iterate
|
||||
|
||||
struct HighFiveIterateData {
|
||||
explicit HighFiveIterateData(std::vector<std::string>& my_names)
|
||||
: names(my_names)
|
||||
, err(nullptr) {}
|
||||
|
||||
std::vector<std::string>& names;
|
||||
std::exception* err;
|
||||
|
||||
inline void throwIfError() const {
|
||||
if (err != nullptr) {
|
||||
throw *err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename InfoType>
|
||||
inline herr_t internal_high_five_iterate(hid_t /*id*/,
|
||||
const char* name,
|
||||
const InfoType* /*info*/,
|
||||
void* op_data) {
|
||||
auto* data = static_cast<HighFiveIterateData*>(op_data);
|
||||
try {
|
||||
data->names.emplace_back(name);
|
||||
return 0;
|
||||
} catch (...) {
|
||||
data->err = new ObjectException("Exception during H5Iterate, abort listing");
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
234
include/highfive/bits/H5Node_traits.hpp
Normal file
234
include/highfive/bits/H5Node_traits.hpp
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
|
||||
#include "../H5PropertyList.hpp"
|
||||
#include "H5_definitions.hpp"
|
||||
#include "H5Converter_misc.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
enum class IndexType : std::underlying_type<H5_index_t>::type {
|
||||
NAME = H5_INDEX_NAME,
|
||||
CRT_ORDER = H5_INDEX_CRT_ORDER,
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief NodeTraits: Base class for Group and File
|
||||
///
|
||||
template <typename Derivate>
|
||||
class NodeTraits {
|
||||
public:
|
||||
///
|
||||
/// \brief createDataSet Create a new dataset in the current file of
|
||||
/// datatype type and of size space
|
||||
/// \param dataset_name identifier of the dataset
|
||||
/// \param space Associated DataSpace, see \ref DataSpace for more information
|
||||
/// \param type Type of Data
|
||||
/// \param createProps A property list with data set creation properties
|
||||
/// \param accessProps A property list with data set access properties
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return DataSet Object
|
||||
DataSet createDataSet(const std::string& dataset_name,
|
||||
const DataSpace& space,
|
||||
const DataType& type,
|
||||
const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
|
||||
const DataSetAccessProps& accessProps = DataSetAccessProps::Default(),
|
||||
bool parents = true);
|
||||
|
||||
///
|
||||
/// \brief createDataSet create a new dataset in the current file with a
|
||||
/// size specified by space
|
||||
/// \param dataset_name identifier of the dataset
|
||||
/// \param space Associated DataSpace, see \ref DataSpace for more information
|
||||
/// \param createProps A property list with data set creation properties
|
||||
/// \param accessProps A property list with data set access properties
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return DataSet Object
|
||||
template <typename T>
|
||||
DataSet createDataSet(const std::string& dataset_name,
|
||||
const DataSpace& space,
|
||||
const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
|
||||
const DataSetAccessProps& accessProps = DataSetAccessProps::Default(),
|
||||
bool parents = true);
|
||||
|
||||
///
|
||||
/// \brief createDataSet create a new dataset in the current file and
|
||||
/// write to it, inferring the DataSpace from the data.
|
||||
/// \param dataset_name identifier of the dataset
|
||||
/// \param data Associated data, must support DataSpace::From, see
|
||||
/// \ref DataSpace for more information
|
||||
/// \param createProps A property list with data set creation properties
|
||||
/// \param accessProps A property list with data set access properties
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return DataSet Object
|
||||
template <typename T>
|
||||
DataSet createDataSet(const std::string& dataset_name,
|
||||
const T& data,
|
||||
const DataSetCreateProps& createProps = DataSetCreateProps::Default(),
|
||||
const DataSetAccessProps& accessProps = DataSetAccessProps::Default(),
|
||||
bool parents = true);
|
||||
|
||||
|
||||
///
|
||||
/// \brief get an existing dataset in the current file
|
||||
/// \param dataset_name
|
||||
/// \param accessProps property list to configure dataset chunk cache
|
||||
/// \return return the named dataset, or throw exception if not found
|
||||
DataSet getDataSet(const std::string& dataset_name,
|
||||
const DataSetAccessProps& accessProps = DataSetAccessProps::Default()) const;
|
||||
|
||||
///
|
||||
/// \brief create a new group, and eventually intermediate groups
|
||||
/// \param group_name
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return the group object
|
||||
Group createGroup(const std::string& group_name, bool parents = true);
|
||||
|
||||
///
|
||||
/// \brief create a new group, and eventually intermediate groups
|
||||
/// \param group_name
|
||||
/// \param createProps A property list with group creation properties
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return the group object
|
||||
Group createGroup(const std::string& group_name,
|
||||
const GroupCreateProps& createProps,
|
||||
bool parents = true);
|
||||
|
||||
///
|
||||
/// \brief open an existing group with the name group_name
|
||||
/// \param group_name
|
||||
/// \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
|
||||
size_t getNumberObjects() const;
|
||||
|
||||
///
|
||||
/// \brief return the name of the object with the given index
|
||||
/// \return the name of the object
|
||||
std::string getObjectName(size_t index) const;
|
||||
|
||||
///
|
||||
/// \brief moves an object and its content within an HDF5 file.
|
||||
/// \param src_path relative path of the object to current File/Group
|
||||
/// \param dst_path new relative path of the object to current File/Group
|
||||
/// \param parents Create intermediate groups if needed. Default: true.
|
||||
/// \return boolean that is true if the move was successful
|
||||
bool rename(const std::string& src_path,
|
||||
const std::string& dst_path,
|
||||
bool parents = true) const;
|
||||
|
||||
///
|
||||
/// \brief list all leaf objects name of the node / group
|
||||
/// \param idx_type tell if the list should be ordered by Name or CreationOrderTime.
|
||||
/// CreationOrderTime can be use only if the file/group has been created with
|
||||
/// the HighFive::LinkCreationTime property.
|
||||
/// \return number of leaf objects
|
||||
std::vector<std::string> listObjectNames(IndexType idx_type = IndexType::NAME) const;
|
||||
|
||||
///
|
||||
/// \brief check a dataset or group exists in the current node / group
|
||||
/// \param node_path dataset/group name to check
|
||||
/// \return true if a dataset/group with the associated name exists, or false
|
||||
bool exist(const std::string& node_path) const;
|
||||
|
||||
///
|
||||
/// \brief unlink the given dataset or group
|
||||
/// \param node_path dataset/group name to unlink
|
||||
void unlink(const std::string& node_path) const;
|
||||
|
||||
///
|
||||
/// \brief Returns the kind of link of the given name (soft, hard...)
|
||||
/// \param node_path The entry to check, path relative to the current group
|
||||
LinkType getLinkType(const std::string& node_path) const;
|
||||
|
||||
///
|
||||
/// \brief A shorthand to get the kind of object pointed to (group, dataset, type...)
|
||||
/// \param node_path The entry to check, path relative to the current group
|
||||
ObjectType getObjectType(const std::string& node_path) const;
|
||||
|
||||
///
|
||||
/// \brief A shorthand to create softlink to any object which provides `getPath`
|
||||
/// The link will be created with default properties along with required parent groups
|
||||
template <typename T, typename = decltype(&T::getPath)>
|
||||
void createSoftLink(const std::string& linkName, const T& obj) {
|
||||
static_assert(!std::is_same<T, Attribute>::value,
|
||||
"hdf5 doesn't support soft links to Attributes");
|
||||
createSoftLink(linkName, obj.getPath());
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Creates softlinks
|
||||
/// \param link_name The name of the link
|
||||
/// \param obj_path The target object path
|
||||
/// \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
|
||||
void createSoftLink(const std::string& link_name,
|
||||
const std::string& obj_path,
|
||||
LinkCreateProps linkCreateProps = LinkCreateProps(),
|
||||
const LinkAccessProps& linkAccessProps = LinkAccessProps(),
|
||||
bool parents = true);
|
||||
|
||||
void createExternalLink(const std::string& link_name,
|
||||
const std::string& h5_file,
|
||||
const std::string& obj_path,
|
||||
LinkCreateProps linkCreateProps = LinkCreateProps(),
|
||||
const LinkAccessProps& linkAccessProps = LinkAccessProps(),
|
||||
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 <typename T, typename = decltype(&T::getPath)>
|
||||
void createHardLink(const std::string& link_name,
|
||||
const T& target_obj,
|
||||
LinkCreateProps linkCreateProps = LinkCreateProps(),
|
||||
const LinkAccessProps& linkAccessProps = LinkAccessProps(),
|
||||
bool parents = true);
|
||||
|
||||
private:
|
||||
using derivate_type = Derivate;
|
||||
|
||||
// A wrapper over the low-level H5Lexist
|
||||
// It makes behavior consistent among versions and by default transforms
|
||||
// errors to exceptions
|
||||
bool _exist(const std::string& node_path, bool raise_errors = true) const;
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief The possible types of group entries (link concept)
|
||||
///
|
||||
enum class LinkType {
|
||||
Hard,
|
||||
Soft,
|
||||
External,
|
||||
Other // Reserved or User-defined
|
||||
};
|
||||
|
||||
|
||||
} // namespace HighFive
|
||||
322
include/highfive/bits/H5Node_traits_misc.hpp
Normal file
322
include/highfive/bits/H5Node_traits_misc.hpp
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <string>
|
||||
#include <vector>
|
||||
|
||||
#include <H5Apublic.h>
|
||||
#include <H5Fpublic.h>
|
||||
#include <H5Ppublic.h>
|
||||
#include <H5Tpublic.h>
|
||||
|
||||
#include "../H5DataSet.hpp"
|
||||
#include "../H5Group.hpp"
|
||||
#include "../H5Selection.hpp"
|
||||
#include "../H5Utility.hpp"
|
||||
#include "H5DataSet_misc.hpp"
|
||||
#include "H5Iterables_misc.hpp"
|
||||
#include "H5Selection_misc.hpp"
|
||||
#include "H5Slice_traits_misc.hpp"
|
||||
|
||||
#include "h5l_wrapper.hpp"
|
||||
#include "h5g_wrapper.hpp"
|
||||
#include "h5o_wrapper.hpp"
|
||||
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
|
||||
const DataSpace& space,
|
||||
const DataType& dtype,
|
||||
const DataSetCreateProps& createProps,
|
||||
const DataSetAccessProps& accessProps,
|
||||
bool parents) {
|
||||
LinkCreateProps lcpl;
|
||||
lcpl.add(CreateIntermediateGroup(parents));
|
||||
return DataSet(detail::h5d_create2(static_cast<Derivate*>(this)->getId(),
|
||||
dataset_name.c_str(),
|
||||
dtype.getId(),
|
||||
space.getId(),
|
||||
lcpl.getId(),
|
||||
createProps.getId(),
|
||||
accessProps.getId()));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
|
||||
const DataSpace& space,
|
||||
const DataSetCreateProps& createProps,
|
||||
const DataSetAccessProps& accessProps,
|
||||
bool parents) {
|
||||
return createDataSet(
|
||||
dataset_name, space, create_and_check_datatype<T>(), createProps, accessProps, parents);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline DataSet NodeTraits<Derivate>::createDataSet(const std::string& dataset_name,
|
||||
const T& data,
|
||||
const DataSetCreateProps& createProps,
|
||||
const DataSetAccessProps& accessProps,
|
||||
bool parents) {
|
||||
DataSet ds =
|
||||
createDataSet(dataset_name,
|
||||
DataSpace::From(data),
|
||||
create_and_check_datatype<typename details::inspector<T>::base_type>(),
|
||||
createProps,
|
||||
accessProps,
|
||||
parents);
|
||||
ds.write(data);
|
||||
return ds;
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline DataSet NodeTraits<Derivate>::getDataSet(const std::string& dataset_name,
|
||||
const DataSetAccessProps& accessProps) const {
|
||||
return DataSet(detail::h5d_open2(static_cast<const Derivate*>(this)->getId(),
|
||||
dataset_name.c_str(),
|
||||
accessProps.getId()));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Group NodeTraits<Derivate>::createGroup(const std::string& group_name, bool parents) {
|
||||
LinkCreateProps lcpl;
|
||||
lcpl.add(CreateIntermediateGroup(parents));
|
||||
return detail::make_group(detail::h5g_create2(static_cast<Derivate*>(this)->getId(),
|
||||
group_name.c_str(),
|
||||
lcpl.getId(),
|
||||
H5P_DEFAULT,
|
||||
H5P_DEFAULT));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Group NodeTraits<Derivate>::createGroup(const std::string& group_name,
|
||||
const GroupCreateProps& createProps,
|
||||
bool parents) {
|
||||
LinkCreateProps lcpl;
|
||||
lcpl.add(CreateIntermediateGroup(parents));
|
||||
return detail::make_group(detail::h5g_create2(static_cast<Derivate*>(this)->getId(),
|
||||
group_name.c_str(),
|
||||
lcpl.getId(),
|
||||
createProps.getId(),
|
||||
H5P_DEFAULT));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Group NodeTraits<Derivate>::getGroup(const std::string& group_name) const {
|
||||
return detail::make_group(detail::h5g_open2(static_cast<const Derivate*>(this)->getId(),
|
||||
group_name.c_str(),
|
||||
H5P_DEFAULT));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline DataType NodeTraits<Derivate>::getDataType(const std::string& type_name,
|
||||
const DataTypeAccessProps& accessProps) const {
|
||||
return DataType(detail::h5t_open2(static_cast<const Derivate*>(this)->getId(),
|
||||
type_name.c_str(),
|
||||
accessProps.getId()));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline size_t NodeTraits<Derivate>::getNumberObjects() const {
|
||||
hsize_t res;
|
||||
detail::h5g_get_num_objs(static_cast<const Derivate*>(this)->getId(), &res);
|
||||
return static_cast<size_t>(res);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline std::string NodeTraits<Derivate>::getObjectName(size_t index) const {
|
||||
return details::get_name([&](char* buffer, size_t length) {
|
||||
return detail::h5l_get_name_by_idx(static_cast<const Derivate*>(this)->getId(),
|
||||
".",
|
||||
H5_INDEX_NAME,
|
||||
H5_ITER_INC,
|
||||
index,
|
||||
buffer,
|
||||
length,
|
||||
H5P_DEFAULT);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline bool NodeTraits<Derivate>::rename(const std::string& src_path,
|
||||
const std::string& dst_path,
|
||||
bool parents) const {
|
||||
LinkCreateProps lcpl;
|
||||
lcpl.add(CreateIntermediateGroup(parents));
|
||||
herr_t err = detail::h5l_move(static_cast<const Derivate*>(this)->getId(),
|
||||
src_path.c_str(),
|
||||
static_cast<const Derivate*>(this)->getId(),
|
||||
dst_path.c_str(),
|
||||
lcpl.getId(),
|
||||
H5P_DEFAULT);
|
||||
|
||||
return err >= 0;
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline std::vector<std::string> NodeTraits<Derivate>::listObjectNames(IndexType idx_type) const {
|
||||
std::vector<std::string> names;
|
||||
details::HighFiveIterateData iterateData(names);
|
||||
|
||||
size_t num_objs = getNumberObjects();
|
||||
names.reserve(num_objs);
|
||||
|
||||
detail::h5l_iterate(static_cast<const Derivate*>(this)->getId(),
|
||||
static_cast<H5_index_t>(idx_type),
|
||||
H5_ITER_INC,
|
||||
NULL,
|
||||
&details::internal_high_five_iterate<H5L_info_t>,
|
||||
static_cast<void*>(&iterateData));
|
||||
return names;
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline bool NodeTraits<Derivate>::_exist(const std::string& node_path, bool raise_errors) const {
|
||||
SilenceHDF5 silencer{};
|
||||
const auto val = detail::nothrow::h5l_exists(static_cast<const Derivate*>(this)->getId(),
|
||||
node_path.c_str(),
|
||||
H5P_DEFAULT);
|
||||
if (val < 0) {
|
||||
if (raise_errors) {
|
||||
HDF5ErrMapper::ToException<GroupException>("Invalid link for exist()");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The root path always exists, but H5Lexists return 0 or 1
|
||||
// depending of the version of HDF5, so always return true for it
|
||||
// We had to call H5Lexists anyway to check that there are no errors
|
||||
return (node_path == "/") ? true : (val > 0);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline bool NodeTraits<Derivate>::exist(const std::string& node_path) const {
|
||||
// When there are slashes, first check everything is fine
|
||||
// so that subsequent errors are only due to missing intermediate groups
|
||||
if (node_path.find('/') != std::string::npos) {
|
||||
_exist("/"); // Shall not throw under normal circumstances
|
||||
// Unless "/" (already checked), verify path exists (not throwing errors)
|
||||
return (node_path == "/") ? true : _exist(node_path, false);
|
||||
}
|
||||
return _exist(node_path);
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline void NodeTraits<Derivate>::unlink(const std::string& node_path) const {
|
||||
detail::h5l_delete(static_cast<const Derivate*>(this)->getId(), node_path.c_str(), H5P_DEFAULT);
|
||||
}
|
||||
|
||||
|
||||
// convert internal link types to enum class.
|
||||
// This function is internal, so H5L_TYPE_ERROR shall be handled in the calling context
|
||||
static inline LinkType _convert_link_type(const H5L_type_t& ltype) noexcept {
|
||||
switch (ltype) {
|
||||
case H5L_TYPE_HARD:
|
||||
return LinkType::Hard;
|
||||
case H5L_TYPE_SOFT:
|
||||
return LinkType::Soft;
|
||||
case H5L_TYPE_EXTERNAL:
|
||||
return LinkType::External;
|
||||
default:
|
||||
// Other link types are possible but are considered strange to HighFive.
|
||||
// see https://support.hdfgroup.org/HDF5/doc/RM/H5L/H5Lregister.htm
|
||||
return LinkType::Other;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline LinkType NodeTraits<Derivate>::getLinkType(const std::string& node_path) const {
|
||||
H5L_info_t linkinfo;
|
||||
detail::h5l_get_info(static_cast<const Derivate*>(this)->getId(),
|
||||
node_path.c_str(),
|
||||
&linkinfo,
|
||||
H5P_DEFAULT);
|
||||
|
||||
if (linkinfo.type == H5L_TYPE_ERROR) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Link type of \"") + node_path +
|
||||
"\" is H5L_TYPE_ERROR");
|
||||
}
|
||||
return _convert_link_type(linkinfo.type);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline ObjectType NodeTraits<Derivate>::getObjectType(const std::string& node_path) const {
|
||||
const auto id = detail::h5o_open(static_cast<const Derivate*>(this)->getId(),
|
||||
node_path.c_str(),
|
||||
H5P_DEFAULT);
|
||||
auto object_type = _convert_object_type(detail::h5i_get_type(id));
|
||||
detail::h5o_close(id);
|
||||
return object_type;
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline void NodeTraits<Derivate>::createSoftLink(const std::string& link_name,
|
||||
const std::string& obj_path,
|
||||
LinkCreateProps linkCreateProps,
|
||||
const LinkAccessProps& linkAccessProps,
|
||||
const bool parents) {
|
||||
if (parents) {
|
||||
linkCreateProps.add(CreateIntermediateGroup{});
|
||||
}
|
||||
detail::h5l_create_soft(obj_path.c_str(),
|
||||
static_cast<const Derivate*>(this)->getId(),
|
||||
link_name.c_str(),
|
||||
linkCreateProps.getId(),
|
||||
linkAccessProps.getId());
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline void NodeTraits<Derivate>::createExternalLink(const std::string& link_name,
|
||||
const std::string& h5_file,
|
||||
const std::string& obj_path,
|
||||
LinkCreateProps linkCreateProps,
|
||||
const LinkAccessProps& linkAccessProps,
|
||||
const bool parents) {
|
||||
if (parents) {
|
||||
linkCreateProps.add(CreateIntermediateGroup{});
|
||||
}
|
||||
detail::h5l_create_external(h5_file.c_str(),
|
||||
obj_path.c_str(),
|
||||
static_cast<const Derivate*>(this)->getId(),
|
||||
link_name.c_str(),
|
||||
linkCreateProps.getId(),
|
||||
linkAccessProps.getId());
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T, typename>
|
||||
inline void NodeTraits<Derivate>::createHardLink(const std::string& link_name,
|
||||
const T& target_obj,
|
||||
LinkCreateProps linkCreateProps,
|
||||
const LinkAccessProps& linkAccessProps,
|
||||
const bool parents) {
|
||||
static_assert(!std::is_same<T, Attribute>::value,
|
||||
"hdf5 doesn't support hard links to Attributes");
|
||||
if (parents) {
|
||||
linkCreateProps.add(CreateIntermediateGroup{});
|
||||
}
|
||||
detail::h5l_create_hard(target_obj.getId(),
|
||||
".",
|
||||
static_cast<const Derivate*>(this)->getId(),
|
||||
link_name.c_str(),
|
||||
linkCreateProps.getId(),
|
||||
linkAccessProps.getId());
|
||||
}
|
||||
|
||||
|
||||
} // namespace HighFive
|
||||
128
include/highfive/bits/H5Object_misc.hpp
Normal file
128
include/highfive/bits/H5Object_misc.hpp
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <iostream>
|
||||
|
||||
#include "../H5Exception.hpp"
|
||||
#include "../H5Utility.hpp"
|
||||
#include "h5i_wrapper.hpp"
|
||||
#include "h5o_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline Object::Object()
|
||||
: _hid(H5I_INVALID_HID) {}
|
||||
|
||||
inline Object::Object(hid_t hid) noexcept
|
||||
: _hid(hid) {}
|
||||
|
||||
inline Object::Object(const Object& other)
|
||||
: _hid(other._hid) {
|
||||
if (other.isValid()) {
|
||||
detail::h5i_inc_ref(_hid);
|
||||
}
|
||||
}
|
||||
|
||||
inline Object::Object(Object&& other) noexcept
|
||||
: _hid(other._hid) {
|
||||
other._hid = H5I_INVALID_HID;
|
||||
}
|
||||
|
||||
inline Object& Object::operator=(Object&& other) {
|
||||
if (this != &other) {
|
||||
if ((*this).isValid()) {
|
||||
detail::h5i_dec_ref(_hid);
|
||||
}
|
||||
_hid = other._hid;
|
||||
other._hid = H5I_INVALID_HID;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Object& Object::operator=(const Object& other) {
|
||||
if (this != &other) {
|
||||
if ((*this).isValid()) {
|
||||
detail::h5i_dec_ref(_hid);
|
||||
}
|
||||
|
||||
_hid = other._hid;
|
||||
if (other.isValid()) {
|
||||
detail::h5i_inc_ref(_hid);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Object::~Object() {
|
||||
if (isValid()) {
|
||||
if (detail::nothrow::h5i_dec_ref(_hid) < 0) {
|
||||
HIGHFIVE_LOG_ERROR("Failed to decrease reference count of HID");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool Object::isValid() const noexcept {
|
||||
return (_hid > 0) && (detail::nothrow::h5i_is_valid(_hid) > 0);
|
||||
}
|
||||
|
||||
inline hid_t Object::getId() const noexcept {
|
||||
return _hid;
|
||||
}
|
||||
|
||||
static inline ObjectType _convert_object_type(const H5I_type_t& h5type) {
|
||||
switch (h5type) {
|
||||
case H5I_FILE:
|
||||
return ObjectType::File;
|
||||
case H5I_GROUP:
|
||||
return ObjectType::Group;
|
||||
case H5I_DATATYPE:
|
||||
return ObjectType::UserDataType;
|
||||
case H5I_DATASPACE:
|
||||
return ObjectType::DataSpace;
|
||||
case H5I_DATASET:
|
||||
return ObjectType::Dataset;
|
||||
case H5I_ATTR:
|
||||
return ObjectType::Attribute;
|
||||
default:
|
||||
return ObjectType::Other;
|
||||
}
|
||||
}
|
||||
|
||||
inline ObjectType Object::getType() const {
|
||||
// H5Iget_type is a very lightweight func which extracts the type from the id
|
||||
return _convert_object_type(detail::h5i_get_type(_hid));
|
||||
}
|
||||
|
||||
inline ObjectInfo Object::getInfo() const {
|
||||
return ObjectInfo(*this);
|
||||
}
|
||||
|
||||
inline haddr_t Object::getAddress() const {
|
||||
detail::h5o_info1_t raw_info;
|
||||
detail::h5o_get_info1(_hid, &raw_info);
|
||||
return raw_info.addr;
|
||||
}
|
||||
|
||||
inline ObjectInfo::ObjectInfo(const Object& obj) {
|
||||
detail::h5o_get_info1(obj.getId(), &raw_info);
|
||||
}
|
||||
|
||||
inline size_t ObjectInfo::getRefCount() const noexcept {
|
||||
return raw_info.rc;
|
||||
}
|
||||
inline time_t ObjectInfo::getCreationTime() const noexcept {
|
||||
return raw_info.btime;
|
||||
}
|
||||
inline time_t ObjectInfo::getModificationTime() const noexcept {
|
||||
return raw_info.mtime;
|
||||
}
|
||||
|
||||
|
||||
} // namespace HighFive
|
||||
34
include/highfive/bits/H5Path_traits.hpp
Normal file
34
include/highfive/bits/H5Path_traits.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c), 2020, EPFL - 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 "H5_definitions.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <typename Derivate>
|
||||
class PathTraits {
|
||||
public:
|
||||
PathTraits();
|
||||
|
||||
///
|
||||
/// \brief return the path to the current object
|
||||
/// \return the path to the object
|
||||
std::string getPath() const;
|
||||
|
||||
///
|
||||
/// \brief Return a reference to the File object this object belongs
|
||||
/// \return the File object ref
|
||||
File& getFile() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<File> _file_obj; // keep a ref to file so we keep its ref count > 0
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
46
include/highfive/bits/H5Path_traits_misc.hpp
Normal file
46
include/highfive/bits/H5Path_traits_misc.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (c), 2020, EPFL - 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 <H5Ipublic.h>
|
||||
|
||||
#include "H5Utils.hpp"
|
||||
#include "H5Path_traits.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
template <typename Derivate>
|
||||
inline PathTraits<Derivate>::PathTraits() {
|
||||
static_assert(std::is_same<Derivate, Group>::value || std::is_same<Derivate, DataSet>::value ||
|
||||
std::is_same<Derivate, Attribute>::value,
|
||||
"PathTraits can only be applied to Group, DataSet and Attribute");
|
||||
const auto& obj = static_cast<const Derivate&>(*this);
|
||||
if (obj.isValid()) {
|
||||
const hid_t file_id = detail::h5i_get_file_id<PropertyException>(obj.getId());
|
||||
_file_obj.reset(new File(file_id));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline std::string PathTraits<Derivate>::getPath() const {
|
||||
return details::get_name([this](char* buffer, size_t length) {
|
||||
return detail::h5i_get_name(static_cast<const Derivate&>(*this).getId(), buffer, length);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline File& PathTraits<Derivate>::getFile() const {
|
||||
const auto& obj = static_cast<const Derivate&>(*this);
|
||||
if (!obj.isValid()) {
|
||||
throw ObjectException("Invalid call to `PathTraits::getFile` for invalid object");
|
||||
}
|
||||
return *_file_obj;
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
492
include/highfive/bits/H5PropertyList_misc.hpp
Normal file
492
include/highfive/bits/H5PropertyList_misc.hpp
Normal file
@ -0,0 +1,492 @@
|
||||
/*
|
||||
* Copyright (c), 2017-2018, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
* Juan Hernando <juan.hernando@epfl.ch>
|
||||
* 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 "h5p_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace {
|
||||
inline hid_t convert_plist_type(PropertyType propertyType) {
|
||||
// The HP5_XXX are macros with function calls so we can't assign
|
||||
// them as the enum values
|
||||
switch (propertyType) {
|
||||
case PropertyType::FILE_CREATE:
|
||||
return H5P_FILE_CREATE;
|
||||
case PropertyType::FILE_ACCESS:
|
||||
return H5P_FILE_ACCESS;
|
||||
case PropertyType::DATASET_CREATE:
|
||||
return H5P_DATASET_CREATE;
|
||||
case PropertyType::DATASET_ACCESS:
|
||||
return H5P_DATASET_ACCESS;
|
||||
case PropertyType::DATASET_XFER:
|
||||
return H5P_DATASET_XFER;
|
||||
case PropertyType::GROUP_CREATE:
|
||||
return H5P_GROUP_CREATE;
|
||||
case PropertyType::GROUP_ACCESS:
|
||||
return H5P_GROUP_ACCESS;
|
||||
case PropertyType::DATATYPE_CREATE:
|
||||
return H5P_DATATYPE_CREATE;
|
||||
case PropertyType::DATATYPE_ACCESS:
|
||||
return H5P_DATATYPE_ACCESS;
|
||||
case PropertyType::STRING_CREATE:
|
||||
return H5P_STRING_CREATE;
|
||||
case PropertyType::ATTRIBUTE_CREATE:
|
||||
return H5P_ATTRIBUTE_CREATE;
|
||||
case PropertyType::LINK_CREATE:
|
||||
return H5P_LINK_CREATE;
|
||||
case PropertyType::LINK_ACCESS:
|
||||
return H5P_LINK_ACCESS;
|
||||
default:
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unsupported property list type");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
inline PropertyListBase::PropertyListBase() noexcept
|
||||
: Object(H5P_DEFAULT) {}
|
||||
|
||||
|
||||
template <PropertyType T>
|
||||
inline void PropertyList<T>::_initializeIfNeeded() {
|
||||
if (_hid != H5P_DEFAULT) {
|
||||
return;
|
||||
}
|
||||
_hid = detail::h5p_create(convert_plist_type(T));
|
||||
}
|
||||
|
||||
template <PropertyType T>
|
||||
template <typename P>
|
||||
inline void PropertyList<T>::add(const P& property) {
|
||||
_initializeIfNeeded();
|
||||
property.apply(_hid);
|
||||
}
|
||||
|
||||
template <PropertyType T>
|
||||
template <typename F, typename... Args>
|
||||
inline void RawPropertyList<T>::add(const F& funct, const Args&... args) {
|
||||
this->_initializeIfNeeded();
|
||||
if (funct(this->_hid, args...) < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting raw hdf5 property.");
|
||||
}
|
||||
}
|
||||
|
||||
// Specific options to be added to Property Lists
|
||||
#if H5_VERSION_GE(1, 10, 1)
|
||||
inline FileSpaceStrategy::FileSpaceStrategy(H5F_fspace_strategy_t strategy,
|
||||
hbool_t persist,
|
||||
hsize_t threshold)
|
||||
: _strategy(strategy)
|
||||
, _persist(persist)
|
||||
, _threshold(threshold) {}
|
||||
|
||||
inline FileSpaceStrategy::FileSpaceStrategy(const FileCreateProps& fcpl) {
|
||||
detail::h5p_get_file_space_strategy(fcpl.getId(), &_strategy, &_persist, &_threshold);
|
||||
}
|
||||
|
||||
inline void FileSpaceStrategy::apply(const hid_t list) const {
|
||||
detail::h5p_set_file_space_strategy(list, _strategy, _persist, _threshold);
|
||||
}
|
||||
|
||||
inline H5F_fspace_strategy_t FileSpaceStrategy::getStrategy() const {
|
||||
return _strategy;
|
||||
}
|
||||
|
||||
inline hbool_t FileSpaceStrategy::getPersist() const {
|
||||
return _persist;
|
||||
}
|
||||
|
||||
inline hsize_t FileSpaceStrategy::getThreshold() const {
|
||||
return _threshold;
|
||||
}
|
||||
|
||||
inline FileSpacePageSize::FileSpacePageSize(hsize_t page_size)
|
||||
: _page_size(page_size) {}
|
||||
|
||||
inline void FileSpacePageSize::apply(const hid_t list) const {
|
||||
detail::h5p_set_file_space_page_size(list, _page_size);
|
||||
}
|
||||
|
||||
inline FileSpacePageSize::FileSpacePageSize(const FileCreateProps& fcpl) {
|
||||
detail::h5p_get_file_space_page_size(fcpl.getId(), &_page_size);
|
||||
}
|
||||
|
||||
inline hsize_t FileSpacePageSize::getPageSize() const {
|
||||
return _page_size;
|
||||
}
|
||||
|
||||
#ifndef H5_HAVE_PARALLEL
|
||||
inline PageBufferSize::PageBufferSize(size_t page_buffer_size,
|
||||
unsigned min_meta_percent,
|
||||
unsigned min_raw_percent)
|
||||
: _page_buffer_size(page_buffer_size)
|
||||
, _min_meta(min_meta_percent)
|
||||
, _min_raw(min_raw_percent) {}
|
||||
|
||||
inline PageBufferSize::PageBufferSize(const FileAccessProps& fapl) {
|
||||
detail::h5p_get_page_buffer_size(fapl.getId(), &_page_buffer_size, &_min_meta, &_min_raw);
|
||||
}
|
||||
|
||||
inline void PageBufferSize::apply(const hid_t list) const {
|
||||
detail::h5p_set_page_buffer_size(list, _page_buffer_size, _min_meta, _min_raw);
|
||||
}
|
||||
|
||||
inline size_t PageBufferSize::getPageBufferSize() const {
|
||||
return _page_buffer_size;
|
||||
}
|
||||
|
||||
inline unsigned PageBufferSize::getMinMetaPercent() const {
|
||||
return _min_meta;
|
||||
}
|
||||
|
||||
inline unsigned PageBufferSize::getMinRawPercent() const {
|
||||
return _min_raw;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
|
||||
inline MPIOFileAccess::MPIOFileAccess(MPI_Comm comm, MPI_Info info)
|
||||
: _comm(comm)
|
||||
, _info(info) {}
|
||||
|
||||
inline void MPIOFileAccess::apply(const hid_t list) const {
|
||||
detail::h5p_set_fapl_mpio(list, _comm, _info);
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 0)
|
||||
inline void MPIOCollectiveMetadata::apply(const hid_t plist) const {
|
||||
auto read = MPIOCollectiveMetadataRead{collective_read_};
|
||||
auto write = MPIOCollectiveMetadataWrite{collective_write_};
|
||||
|
||||
read.apply(plist);
|
||||
write.apply(plist);
|
||||
}
|
||||
|
||||
inline MPIOCollectiveMetadata::MPIOCollectiveMetadata(bool collective)
|
||||
: collective_read_(collective)
|
||||
, collective_write_(collective) {}
|
||||
|
||||
|
||||
inline MPIOCollectiveMetadata::MPIOCollectiveMetadata(const FileAccessProps& plist)
|
||||
: collective_read_(MPIOCollectiveMetadataRead(plist).isCollective())
|
||||
, collective_write_(MPIOCollectiveMetadataWrite(plist).isCollective()) {}
|
||||
|
||||
inline bool MPIOCollectiveMetadata::isCollectiveRead() const {
|
||||
return collective_read_;
|
||||
}
|
||||
|
||||
inline bool MPIOCollectiveMetadata::isCollectiveWrite() const {
|
||||
return collective_write_;
|
||||
}
|
||||
|
||||
|
||||
inline void MPIOCollectiveMetadataRead::apply(const hid_t plist) const {
|
||||
detail::h5p_set_all_coll_metadata_ops(plist, collective_);
|
||||
}
|
||||
|
||||
inline bool MPIOCollectiveMetadataRead::isCollective() const {
|
||||
return collective_;
|
||||
}
|
||||
|
||||
inline MPIOCollectiveMetadataRead::MPIOCollectiveMetadataRead(const FileAccessProps& plist) {
|
||||
detail::h5p_get_all_coll_metadata_ops(plist.getId(), &collective_);
|
||||
}
|
||||
|
||||
inline MPIOCollectiveMetadataRead::MPIOCollectiveMetadataRead(bool collective)
|
||||
: collective_(collective) {}
|
||||
|
||||
inline void MPIOCollectiveMetadataWrite::apply(const hid_t plist) const {
|
||||
detail::h5p_set_coll_metadata_write(plist, collective_);
|
||||
}
|
||||
|
||||
inline bool MPIOCollectiveMetadataWrite::isCollective() const {
|
||||
return collective_;
|
||||
}
|
||||
|
||||
inline MPIOCollectiveMetadataWrite::MPIOCollectiveMetadataWrite(const FileAccessProps& plist) {
|
||||
detail::h5p_get_coll_metadata_write(plist.getId(), &collective_);
|
||||
}
|
||||
|
||||
inline MPIOCollectiveMetadataWrite::MPIOCollectiveMetadataWrite(bool collective)
|
||||
: collective_(collective) {}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline FileVersionBounds::FileVersionBounds(H5F_libver_t low, H5F_libver_t high)
|
||||
: _low(low)
|
||||
, _high(high) {}
|
||||
|
||||
inline FileVersionBounds::FileVersionBounds(const FileAccessProps& fapl) {
|
||||
detail::h5p_get_libver_bounds(fapl.getId(), &_low, &_high);
|
||||
}
|
||||
|
||||
inline std::pair<H5F_libver_t, H5F_libver_t> FileVersionBounds::getVersion() const {
|
||||
return std::make_pair(_low, _high);
|
||||
}
|
||||
|
||||
inline void FileVersionBounds::apply(const hid_t list) const {
|
||||
detail::h5p_set_libver_bounds(list, _low, _high);
|
||||
}
|
||||
|
||||
inline MetadataBlockSize::MetadataBlockSize(hsize_t size)
|
||||
: _size(size) {}
|
||||
|
||||
inline MetadataBlockSize::MetadataBlockSize(const FileAccessProps& fapl) {
|
||||
detail::h5p_get_meta_block_size(fapl.getId(), &_size);
|
||||
}
|
||||
|
||||
inline void MetadataBlockSize::apply(const hid_t list) const {
|
||||
detail::h5p_set_meta_block_size(list, _size);
|
||||
}
|
||||
|
||||
inline hsize_t MetadataBlockSize::getSize() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
inline void EstimatedLinkInfo::apply(const hid_t hid) const {
|
||||
detail::h5p_set_est_link_info(hid, _entries, _length);
|
||||
}
|
||||
|
||||
inline EstimatedLinkInfo::EstimatedLinkInfo(unsigned entries, unsigned length)
|
||||
: _entries(entries)
|
||||
, _length(length) {}
|
||||
|
||||
inline EstimatedLinkInfo::EstimatedLinkInfo(const GroupCreateProps& gcpl) {
|
||||
detail::h5p_get_est_link_info(gcpl.getId(), &_entries, &_length);
|
||||
}
|
||||
|
||||
inline unsigned EstimatedLinkInfo::getEntries() const {
|
||||
return _entries;
|
||||
}
|
||||
|
||||
inline unsigned EstimatedLinkInfo::getNameLength() const {
|
||||
return _length;
|
||||
}
|
||||
|
||||
inline void Chunking::apply(const hid_t hid) const {
|
||||
detail::h5p_set_chunk(hid, static_cast<int>(_dims.size()), _dims.data());
|
||||
}
|
||||
|
||||
inline Chunking::Chunking(const std::vector<hsize_t>& dims)
|
||||
: _dims(dims) {}
|
||||
|
||||
inline Chunking::Chunking(const std::initializer_list<hsize_t>& items)
|
||||
: Chunking(std::vector<hsize_t>{items}) {}
|
||||
|
||||
inline Chunking::Chunking(DataSetCreateProps& plist, size_t max_dims)
|
||||
: _dims(max_dims + 1) {
|
||||
auto n_loaded =
|
||||
detail::h5p_get_chunk(plist.getId(), static_cast<int>(_dims.size()), _dims.data());
|
||||
|
||||
if (n_loaded >= static_cast<int>(_dims.size())) {
|
||||
*this = Chunking(plist, 8 * max_dims);
|
||||
} else {
|
||||
_dims.resize(static_cast<size_t>(n_loaded));
|
||||
}
|
||||
}
|
||||
|
||||
inline const std::vector<hsize_t>& Chunking::getDimensions() const {
|
||||
return _dims;
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline Chunking::Chunking(hsize_t item, Args... args)
|
||||
: Chunking(std::vector<hsize_t>{item, static_cast<hsize_t>(args)...}) {}
|
||||
|
||||
inline void Deflate::apply(const hid_t hid) const {
|
||||
if (detail::h5z_filter_avail(H5Z_FILTER_DEFLATE) == 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Deflate filter unavailable.");
|
||||
}
|
||||
|
||||
detail::h5p_set_deflate(hid, _level);
|
||||
}
|
||||
|
||||
inline Deflate::Deflate(unsigned int level)
|
||||
: _level(level) {}
|
||||
|
||||
inline void Szip::apply(const hid_t hid) const {
|
||||
if (detail::h5z_filter_avail(H5Z_FILTER_SZIP) == 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("SZIP filter unavailable.");
|
||||
}
|
||||
|
||||
detail::h5p_set_szip(hid, _options_mask, _pixels_per_block);
|
||||
}
|
||||
|
||||
inline Szip::Szip(unsigned int options_mask, unsigned int pixels_per_block)
|
||||
: _options_mask(options_mask)
|
||||
, _pixels_per_block(pixels_per_block) {}
|
||||
|
||||
inline unsigned Szip::getOptionsMask() const {
|
||||
return _options_mask;
|
||||
}
|
||||
|
||||
inline unsigned Szip::getPixelsPerBlock() const {
|
||||
return _pixels_per_block;
|
||||
}
|
||||
|
||||
inline void Shuffle::apply(const hid_t hid) const {
|
||||
if (detail::h5z_filter_avail(H5Z_FILTER_SHUFFLE) == 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Shuffle filter unavailable.");
|
||||
}
|
||||
|
||||
detail::h5p_set_shuffle(hid);
|
||||
}
|
||||
|
||||
inline AllocationTime::AllocationTime(H5D_alloc_time_t alloc_time)
|
||||
: _alloc_time(alloc_time) {}
|
||||
|
||||
inline AllocationTime::AllocationTime(const DataSetCreateProps& dcpl) {
|
||||
detail::h5p_get_alloc_time(dcpl.getId(), &_alloc_time);
|
||||
}
|
||||
|
||||
inline void AllocationTime::apply(hid_t dcpl) const {
|
||||
detail::h5p_set_alloc_time(dcpl, _alloc_time);
|
||||
}
|
||||
|
||||
inline H5D_alloc_time_t AllocationTime::getAllocationTime() {
|
||||
return _alloc_time;
|
||||
}
|
||||
|
||||
inline Caching::Caching(const DataSetCreateProps& dcpl) {
|
||||
detail::h5p_get_chunk_cache(dcpl.getId(), &_numSlots, &_cacheSize, &_w0);
|
||||
}
|
||||
|
||||
inline void Caching::apply(const hid_t hid) const {
|
||||
detail::h5p_set_chunk_cache(hid, _numSlots, _cacheSize, _w0);
|
||||
}
|
||||
|
||||
inline Caching::Caching(const size_t numSlots, const size_t cacheSize, const double w0)
|
||||
: _numSlots(numSlots)
|
||||
, _cacheSize(cacheSize)
|
||||
, _w0(w0) {}
|
||||
|
||||
inline size_t Caching::getNumSlots() const {
|
||||
return _numSlots;
|
||||
}
|
||||
|
||||
inline size_t Caching::getCacheSize() const {
|
||||
return _cacheSize;
|
||||
}
|
||||
|
||||
inline double Caching::getW0() const {
|
||||
return _w0;
|
||||
}
|
||||
|
||||
inline CreateIntermediateGroup::CreateIntermediateGroup(bool create)
|
||||
: _create(create) {}
|
||||
|
||||
inline void CreateIntermediateGroup::apply(const hid_t hid) const {
|
||||
detail::h5p_set_create_intermediate_group(hid, _create ? 1 : 0);
|
||||
}
|
||||
|
||||
inline CreateIntermediateGroup::CreateIntermediateGroup(const LinkCreateProps& lcpl) {
|
||||
fromPropertyList(lcpl.getId());
|
||||
}
|
||||
|
||||
inline void CreateIntermediateGroup::fromPropertyList(hid_t hid) {
|
||||
unsigned c_bool = 0;
|
||||
_create = bool(detail::h5p_get_create_intermediate_group(hid, &c_bool));
|
||||
}
|
||||
|
||||
inline bool CreateIntermediateGroup::isSet() const {
|
||||
return _create;
|
||||
}
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
inline UseCollectiveIO::UseCollectiveIO(bool enable)
|
||||
: _enable(enable) {}
|
||||
|
||||
inline void UseCollectiveIO::apply(const hid_t hid) const {
|
||||
detail::h5p_set_dxpl_mpio(hid, _enable ? H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT);
|
||||
}
|
||||
|
||||
inline UseCollectiveIO::UseCollectiveIO(const DataTransferProps& dxpl) {
|
||||
H5FD_mpio_xfer_t collective;
|
||||
|
||||
detail::h5p_get_dxpl_mpio(dxpl.getId(), &collective);
|
||||
|
||||
if (collective != H5FD_MPIO_COLLECTIVE && collective != H5FD_MPIO_INDEPENDENT) {
|
||||
throw std::logic_error("H5Pget_dxpl_mpio returned something strange.");
|
||||
}
|
||||
|
||||
_enable = collective == H5FD_MPIO_COLLECTIVE;
|
||||
}
|
||||
|
||||
inline bool UseCollectiveIO::isCollective() const {
|
||||
return _enable;
|
||||
}
|
||||
|
||||
inline MpioNoCollectiveCause::MpioNoCollectiveCause(const DataTransferProps& dxpl) {
|
||||
detail::h5p_get_mpio_no_collective_cause(dxpl.getId(), &_local_cause, &_global_cause);
|
||||
}
|
||||
|
||||
inline bool MpioNoCollectiveCause::wasCollective() const {
|
||||
return _local_cause == 0 && _global_cause == 0;
|
||||
}
|
||||
|
||||
inline uint32_t MpioNoCollectiveCause::getLocalCause() const {
|
||||
return _local_cause;
|
||||
}
|
||||
|
||||
inline uint32_t MpioNoCollectiveCause::getGlobalCause() const {
|
||||
return _global_cause;
|
||||
}
|
||||
|
||||
inline std::pair<uint32_t, uint32_t> MpioNoCollectiveCause::getCause() const {
|
||||
return {_local_cause, _global_cause};
|
||||
}
|
||||
#endif
|
||||
|
||||
inline LinkCreationOrder::LinkCreationOrder(const FileCreateProps& fcpl) {
|
||||
fromPropertyList(fcpl.getId());
|
||||
}
|
||||
|
||||
inline LinkCreationOrder::LinkCreationOrder(const GroupCreateProps& gcpl) {
|
||||
fromPropertyList(gcpl.getId());
|
||||
}
|
||||
|
||||
inline unsigned LinkCreationOrder::getFlags() const {
|
||||
return _flags;
|
||||
}
|
||||
|
||||
inline void LinkCreationOrder::apply(const hid_t hid) const {
|
||||
detail::h5p_set_link_creation_order(hid, _flags);
|
||||
}
|
||||
|
||||
inline void LinkCreationOrder::fromPropertyList(hid_t hid) {
|
||||
detail::h5p_get_link_creation_order(hid, &_flags);
|
||||
}
|
||||
|
||||
inline AttributePhaseChange::AttributePhaseChange(unsigned max_compact, unsigned min_dense)
|
||||
: _max_compact(max_compact)
|
||||
, _min_dense(min_dense) {}
|
||||
|
||||
inline AttributePhaseChange::AttributePhaseChange(const GroupCreateProps& gcpl) {
|
||||
detail::h5p_get_attr_phase_change(gcpl.getId(), &_max_compact, &_min_dense);
|
||||
}
|
||||
|
||||
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 {
|
||||
detail::h5p_set_attr_phase_change(hid, _max_compact, _min_dense);
|
||||
}
|
||||
|
||||
|
||||
} // namespace HighFive
|
||||
181
include/highfive/bits/H5ReadWrite_misc.hpp
Normal file
181
include/highfive/bits/H5ReadWrite_misc.hpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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)
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <H5Tpublic.h>
|
||||
#include "H5Inspector_misc.hpp"
|
||||
#include "H5Utils.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace details {
|
||||
|
||||
template <typename T>
|
||||
using unqualified_t = typename std::remove_const<typename std::remove_reference<T>::type>::type;
|
||||
|
||||
// Find the type of an eventual char array, otherwise void
|
||||
template <typename T>
|
||||
struct type_char_array {
|
||||
using type = typename std::conditional<
|
||||
std::is_same<typename inspector<T>::base_type, std::string>::value,
|
||||
std::string,
|
||||
void>::type;
|
||||
static constexpr bool is_char_array = false;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct type_char_array<T*> {
|
||||
using type = typename std::conditional<std::is_same<unqualified_t<T>, char>::value,
|
||||
char*,
|
||||
typename type_char_array<T>::type>::type;
|
||||
static constexpr bool is_char_array = true;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
struct type_char_array<T[N]> {
|
||||
using type = typename std::conditional<std::is_same<unqualified_t<T>, char>::value,
|
||||
char[N],
|
||||
typename type_char_array<T>::type>::type;
|
||||
static constexpr bool is_char_array = true;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct BufferInfo {
|
||||
using type_no_const = typename std::remove_const<T>::type;
|
||||
using elem_type = typename details::inspector<type_no_const>::base_type;
|
||||
using char_array_t = typename details::type_char_array<type_no_const>::type;
|
||||
static constexpr bool is_char_array = details::type_char_array<type_no_const>::is_char_array;
|
||||
|
||||
enum class Operation { read, write };
|
||||
const Operation op;
|
||||
|
||||
template <class F>
|
||||
BufferInfo(const DataType& file_data_type, F getName, Operation _op);
|
||||
|
||||
size_t getRank(const T& array) const;
|
||||
size_t getMinRank() const;
|
||||
size_t getMaxRank() const;
|
||||
|
||||
// member data for info depending on the destination dataset type
|
||||
const bool is_fixed_len_string;
|
||||
const DataType data_type;
|
||||
const size_t rank_correction;
|
||||
};
|
||||
|
||||
// details implementation
|
||||
template <typename SrcStrT>
|
||||
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.
|
||||
|
||||
bool is_dst_string = detail::h5t_get_class(dst.getId()) == H5T_STRING;
|
||||
bool is_src_string = detail::h5t_get_class(src.getId()) == H5T_STRING;
|
||||
|
||||
if (is_dst_string && is_src_string) {
|
||||
if (detail::h5t_get_cset(src.getId()) == H5T_CSET_ASCII) {
|
||||
detail::h5t_set_cset(dst.getId(), H5T_CSET_ASCII);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
struct string_type_checker<void> {
|
||||
inline static DataType getDataType(const DataType& element_type, const DataType& dtype) {
|
||||
if (detail::h5t_get_class(element_type.getId()) == H5T_STRING) {
|
||||
enforce_ascii_hack(element_type, dtype);
|
||||
}
|
||||
return element_type;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_type_checker<std::string> {
|
||||
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 <std::size_t FixedLen>
|
||||
struct string_type_checker<char[FixedLen]> {
|
||||
inline static DataType getDataType(const DataType& element_type, const DataType& dtype) {
|
||||
DataType return_type = (dtype.isFixedLenStr()) ? AtomicType<char[FixedLen]>()
|
||||
: element_type;
|
||||
enforce_ascii_hack(return_type, dtype);
|
||||
return return_type;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct string_type_checker<char*> {
|
||||
inline static DataType getDataType(const DataType&, const DataType& dtype) {
|
||||
if (dtype.isFixedLenStr()) {
|
||||
throw DataSetException("Can't output variable-length to fixed-length strings");
|
||||
}
|
||||
DataType return_type = AtomicType<std::string>();
|
||||
enforce_ascii_hack(return_type, dtype);
|
||||
return return_type;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
template <class F>
|
||||
BufferInfo<T>::BufferInfo(const DataType& file_data_type, F getName, Operation _op)
|
||||
: op(_op)
|
||||
, is_fixed_len_string(file_data_type.isFixedLenStr())
|
||||
// In case we are using Fixed-len strings we need to subtract one dimension
|
||||
, data_type(string_type_checker<char_array_t>::getDataType(create_datatype<elem_type>(),
|
||||
file_data_type))
|
||||
, rank_correction((is_fixed_len_string && is_char_array) ? 1 : 0) {
|
||||
// We warn. In case they are really not convertible an exception will rise on read/write
|
||||
if (file_data_type.getClass() != data_type.getClass()) {
|
||||
HIGHFIVE_LOG_WARN(getName() + "\": data and hdf5 dataset have different types: " +
|
||||
data_type.string() + " -> " + file_data_type.string());
|
||||
} else if ((file_data_type.getClass() & data_type.getClass()) == DataTypeClass::Float) {
|
||||
HIGHFIVE_LOG_WARN_IF(
|
||||
(op == Operation::read) && (file_data_type.getSize() > data_type.getSize()),
|
||||
getName() + "\": hdf5 dataset has higher floating point precision than data on read: " +
|
||||
file_data_type.string() + " -> " + data_type.string());
|
||||
|
||||
HIGHFIVE_LOG_WARN_IF(
|
||||
(op == Operation::write) && (file_data_type.getSize() < data_type.getSize()),
|
||||
getName() +
|
||||
"\": data has higher floating point precision than hdf5 dataset on write: " +
|
||||
data_type.string() + " -> " + file_data_type.string());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t BufferInfo<T>::getRank(const T& array) const {
|
||||
return details::inspector<type_no_const>::getRank(array) - rank_correction;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t BufferInfo<T>::getMinRank() const {
|
||||
return details::inspector<T>::min_ndim - rank_correction;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
size_t BufferInfo<T>::getMaxRank() const {
|
||||
return details::inspector<T>::max_ndim - rank_correction;
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
} // namespace HighFive
|
||||
58
include/highfive/bits/H5Reference_misc.hpp
Normal file
58
include/highfive/bits/H5Reference_misc.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c), 2020, EPFL - 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 <string>
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
#include "H5Utils.hpp"
|
||||
|
||||
#include "../H5Object.hpp"
|
||||
|
||||
#include "h5r_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline Reference::Reference(const Object& location, const Object& object)
|
||||
: parent_id(location.getId()) {
|
||||
obj_name = details::get_name([&](char* buffer, size_t length) {
|
||||
return detail::h5i_get_name(object.getId(), buffer, length);
|
||||
});
|
||||
}
|
||||
|
||||
inline void Reference::create_ref(hobj_ref_t* refptr) const {
|
||||
detail::h5r_create(refptr, parent_id, obj_name.c_str(), H5R_OBJECT, -1);
|
||||
}
|
||||
|
||||
inline ObjectType Reference::getType(const Object& location) const {
|
||||
return get_ref(location).getType();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T Reference::dereference(const Object& location) const {
|
||||
static_assert(std::is_same<DataSet, T>::value || std::is_same<Group, T>::value,
|
||||
"We can only (de)reference HighFive::Group or HighFive:DataSet");
|
||||
auto obj = get_ref(location);
|
||||
if (obj.getType() != T::type) {
|
||||
HDF5ErrMapper::ToException<ReferenceException>("Trying to dereference the wrong type");
|
||||
}
|
||||
return T(std::move(obj));
|
||||
}
|
||||
|
||||
inline Object Reference::get_ref(const Object& location) const {
|
||||
#if (H5Rdereference_vers == 2)
|
||||
hid_t res = detail::h5r_dereference(location.getId(), H5P_DEFAULT, H5R_OBJECT, &href);
|
||||
#else
|
||||
hid_t res = detail::h5r_dereference(location.getId(), H5R_OBJECT, &href);
|
||||
#endif
|
||||
return Object(res);
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
49
include/highfive/bits/H5Selection_misc.hpp
Normal file
49
include/highfive/bits/H5Selection_misc.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline Selection::Selection(const DataSpace& memspace,
|
||||
const DataSpace& file_space,
|
||||
const DataSet& set)
|
||||
: _mem_space(memspace)
|
||||
, _file_space(file_space)
|
||||
, _set(set) {}
|
||||
|
||||
inline DataSpace Selection::getSpace() const {
|
||||
return _file_space;
|
||||
}
|
||||
|
||||
inline DataSpace Selection::getMemSpace() const {
|
||||
return _mem_space;
|
||||
}
|
||||
|
||||
inline DataSet& Selection::getDataset() {
|
||||
return _set;
|
||||
}
|
||||
|
||||
inline const DataSet& Selection::getDataset() const {
|
||||
return _set;
|
||||
}
|
||||
|
||||
// Not only a shortcut but also for templated compat with H5Dataset
|
||||
inline DataType Selection::getDataType() const {
|
||||
return _set.getDataType();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
inline Selection make_selection(const DataSpace& mem_space,
|
||||
const DataSpace& file_space,
|
||||
const DataSet& set) {
|
||||
return Selection(mem_space, file_space, set);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace HighFive
|
||||
578
include/highfive/bits/H5Slice_traits.hpp
Normal file
578
include/highfive/bits/H5Slice_traits.hpp
Normal file
@ -0,0 +1,578 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "H5_definitions.hpp"
|
||||
#include "H5Utils.hpp"
|
||||
#include "convert_size_vector.hpp"
|
||||
|
||||
#include "../H5PropertyList.hpp"
|
||||
#include "h5s_wrapper.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
class ElementSet {
|
||||
public:
|
||||
///
|
||||
/// \brief Create a list of points of N-dimension for selection.
|
||||
///
|
||||
/// \param list List of continuous coordinates (e.g.: in 2 dimensions space
|
||||
/// `ElementSet{1, 2, 3 ,4}` creates points `(1, 2)` and `(3, 4)`).
|
||||
ElementSet(std::initializer_list<std::size_t> list);
|
||||
///
|
||||
/// \brief Create a list of points of N-dimension for selection.
|
||||
///
|
||||
/// \param list List of N-dim points.
|
||||
ElementSet(std::initializer_list<std::vector<std::size_t>> list);
|
||||
///
|
||||
/// \brief Create a list of points of N-dimension for selection.
|
||||
///
|
||||
/// \param element_ids List of continuous coordinates (e.g.: in 2 dimensions space
|
||||
/// `ElementSet{1, 2, 3 ,4}` creates points `(1, 2)` and `(3, 4)`).
|
||||
explicit ElementSet(const std::vector<std::size_t>& element_ids);
|
||||
///
|
||||
/// \brief Create a list of points of N-dimension for selection.
|
||||
///
|
||||
/// \param element_ids List of N-dim points.
|
||||
explicit ElementSet(const std::vector<std::vector<std::size_t>>& element_ids);
|
||||
|
||||
private:
|
||||
std::vector<std::size_t> _ids;
|
||||
|
||||
template <typename Derivate>
|
||||
friend class SliceTraits;
|
||||
};
|
||||
|
||||
inline std::vector<hsize_t> toHDF5SizeVector(const std::vector<size_t>& from) {
|
||||
return detail::convertSizeVector<hsize_t>(from);
|
||||
}
|
||||
|
||||
inline std::vector<size_t> toSTLSizeVector(const std::vector<hsize_t>& from) {
|
||||
return detail::convertSizeVector<size_t>(from);
|
||||
}
|
||||
|
||||
struct RegularHyperSlab {
|
||||
RegularHyperSlab() = default;
|
||||
|
||||
explicit RegularHyperSlab(const std::vector<size_t>& offset_,
|
||||
const std::vector<size_t>& count_ = {},
|
||||
const std::vector<size_t>& stride_ = {},
|
||||
const std::vector<size_t>& block_ = {})
|
||||
: offset(toHDF5SizeVector(offset_))
|
||||
, count(toHDF5SizeVector(count_))
|
||||
, stride(toHDF5SizeVector(stride_))
|
||||
, block(toHDF5SizeVector(block_)) {}
|
||||
|
||||
static RegularHyperSlab fromHDF5Sizes(std::vector<hsize_t> offset_,
|
||||
std::vector<hsize_t> count_ = {},
|
||||
std::vector<hsize_t> stride_ = {},
|
||||
std::vector<hsize_t> block_ = {}) {
|
||||
RegularHyperSlab slab;
|
||||
slab.offset = std::move(offset_);
|
||||
slab.count = std::move(count_);
|
||||
slab.stride = std::move(stride_);
|
||||
slab.block = std::move(block_);
|
||||
|
||||
return slab;
|
||||
}
|
||||
|
||||
size_t rank() const {
|
||||
return std::max(std::max(offset.size(), count.size()),
|
||||
std::max(stride.size(), block.size()));
|
||||
}
|
||||
|
||||
/// Dimensions when all gaps are removed.
|
||||
std::vector<size_t> packedDims() const {
|
||||
auto n_dims = rank();
|
||||
auto dims = std::vector<size_t>(n_dims, 0);
|
||||
|
||||
for (size_t i = 0; i < n_dims; ++i) {
|
||||
dims[i] = count[i] * (block.empty() ? 1 : block[i]);
|
||||
}
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
std::vector<hsize_t> offset;
|
||||
std::vector<hsize_t> count;
|
||||
std::vector<hsize_t> stride;
|
||||
std::vector<hsize_t> block;
|
||||
};
|
||||
|
||||
class HyperSlab {
|
||||
public:
|
||||
HyperSlab() {
|
||||
selects.emplace_back(RegularHyperSlab{}, Op::None);
|
||||
};
|
||||
|
||||
explicit HyperSlab(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::Set);
|
||||
}
|
||||
|
||||
HyperSlab operator|(const RegularHyperSlab& sel) const {
|
||||
auto ret = *this;
|
||||
ret |= sel;
|
||||
return ret;
|
||||
}
|
||||
|
||||
HyperSlab& operator|=(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::Or);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HyperSlab operator&(const RegularHyperSlab& sel) const {
|
||||
auto ret = *this;
|
||||
ret &= sel;
|
||||
return ret;
|
||||
}
|
||||
|
||||
HyperSlab& operator&=(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::And);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HyperSlab operator^(const RegularHyperSlab& sel) const {
|
||||
auto ret = *this;
|
||||
ret ^= sel;
|
||||
return ret;
|
||||
}
|
||||
|
||||
HyperSlab& operator^=(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::Xor);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HyperSlab& notA(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::NotA);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HyperSlab& notB(const RegularHyperSlab& sel) {
|
||||
selects.emplace_back(sel, Op::NotB);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DataSpace apply(const DataSpace& space_) const {
|
||||
return apply_impl(space_);
|
||||
}
|
||||
|
||||
private:
|
||||
enum class Op {
|
||||
Noop,
|
||||
Set,
|
||||
Or,
|
||||
And,
|
||||
Xor,
|
||||
NotB,
|
||||
NotA,
|
||||
Append,
|
||||
Prepend,
|
||||
Invalid,
|
||||
None,
|
||||
};
|
||||
|
||||
H5S_seloper_t convert(Op op) const {
|
||||
switch (op) {
|
||||
case Op::Noop:
|
||||
return H5S_SELECT_NOOP;
|
||||
case Op::Set:
|
||||
return H5S_SELECT_SET;
|
||||
case Op::Or:
|
||||
return H5S_SELECT_OR;
|
||||
case Op::And:
|
||||
return H5S_SELECT_AND;
|
||||
case Op::Xor:
|
||||
return H5S_SELECT_XOR;
|
||||
case Op::NotB:
|
||||
return H5S_SELECT_NOTB;
|
||||
case Op::NotA:
|
||||
return H5S_SELECT_NOTA;
|
||||
case Op::Append:
|
||||
return H5S_SELECT_APPEND;
|
||||
case Op::Prepend:
|
||||
return H5S_SELECT_PREPEND;
|
||||
case Op::Invalid:
|
||||
return H5S_SELECT_INVALID;
|
||||
default:
|
||||
throw DataSpaceException("Invalid HyperSlab operation.");
|
||||
}
|
||||
}
|
||||
|
||||
struct Select_: public RegularHyperSlab {
|
||||
Select_(const RegularHyperSlab& sel, Op op_)
|
||||
: RegularHyperSlab(sel)
|
||||
, op(op_) {}
|
||||
|
||||
Op op;
|
||||
};
|
||||
|
||||
std::vector<Select_> selects;
|
||||
|
||||
protected:
|
||||
DataSpace select_none(const DataSpace& outer_space) const {
|
||||
auto space = outer_space.clone();
|
||||
detail::h5s_select_none(space.getId());
|
||||
return space;
|
||||
}
|
||||
|
||||
void select_hyperslab(DataSpace& space, const Select_& sel) const {
|
||||
detail::h5s_select_hyperslab(space.getId(),
|
||||
convert(sel.op),
|
||||
sel.offset.empty() ? nullptr : sel.offset.data(),
|
||||
sel.stride.empty() ? nullptr : sel.stride.data(),
|
||||
sel.count.empty() ? nullptr : sel.count.data(),
|
||||
sel.block.empty() ? nullptr : sel.block.data());
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 6)
|
||||
/// The length of a stream of `Op::Or` starting at `begin`.
|
||||
size_t detect_streak(Select_ const* begin, Select_ const* end, Op op) const {
|
||||
assert(op == Op::Or);
|
||||
auto const* it =
|
||||
std::find_if(begin, end, [op](const Select_& sel) { return sel.op != op; });
|
||||
return static_cast<size_t>(it - begin);
|
||||
}
|
||||
|
||||
DataSpace combine_selections(const DataSpace& left_space,
|
||||
Op op,
|
||||
const DataSpace& right_space) const {
|
||||
assert(op == Op::Or);
|
||||
|
||||
auto left_type = detail::h5s_get_select_type(left_space.getId());
|
||||
auto right_type = detail::h5s_get_select_type(right_space.getId());
|
||||
|
||||
// Since HDF5 doesn't allow `combine_selections` with a None
|
||||
// selection, we need to avoid the issue:
|
||||
if (left_type == H5S_SEL_NONE) {
|
||||
return right_space;
|
||||
} else if (right_type == H5S_SEL_NONE) {
|
||||
return left_space;
|
||||
} else if (left_type == H5S_SEL_ALL) {
|
||||
return left_space;
|
||||
} else if (right_type == H5S_SEL_ALL) {
|
||||
return right_space;
|
||||
} else {
|
||||
return detail::make_data_space(
|
||||
detail::h5s_combine_select(left_space.getId(), convert(op), right_space.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
/// Reduce a sequence of `Op::Or` efficiently.
|
||||
///
|
||||
/// The issue is that `H5Sselect_hyperslab` runs in time that linear of the
|
||||
/// number of block in the existing selection. Therefore, a loop that adds
|
||||
/// slab-by-slab has quadratic runtime in the number of slabs.
|
||||
///
|
||||
/// Fortunately, `H5Scombine_select` doesn't suffer from the same problem.
|
||||
/// However, it's only available in 1.10.6 and newer.
|
||||
///
|
||||
/// The solution is to use divide-and-conquer to reduce (long) streaks of
|
||||
/// `Op::Or` in what seems to be log-linear time.
|
||||
DataSpace reduce_streak(const DataSpace& outer_space,
|
||||
Select_ const* begin,
|
||||
Select_ const* end,
|
||||
Op op) const {
|
||||
assert(op == Op::Or);
|
||||
|
||||
if (begin == end) {
|
||||
throw std::runtime_error("Broken logic in 'DataSpace::reduce_streak'.");
|
||||
}
|
||||
|
||||
std::ptrdiff_t distance = end - begin;
|
||||
if (distance == 1) {
|
||||
auto space = select_none(outer_space);
|
||||
select_hyperslab(space, *begin);
|
||||
return space;
|
||||
}
|
||||
|
||||
Select_ const* mid = begin + distance / 2;
|
||||
auto right_space = reduce_streak(outer_space, begin, mid, op);
|
||||
auto left_space = reduce_streak(outer_space, mid, end, op);
|
||||
|
||||
return combine_selections(left_space, op, right_space);
|
||||
}
|
||||
|
||||
DataSpace apply_impl(const DataSpace& space_) const {
|
||||
auto space = space_.clone();
|
||||
auto n_selects = selects.size();
|
||||
for (size_t i = 0; i < n_selects; ++i) {
|
||||
auto const* const begin = selects.data() + i;
|
||||
auto const* const end = selects.data() + n_selects;
|
||||
|
||||
auto n_ors = detect_streak(begin, end, Op::Or);
|
||||
|
||||
if (n_ors > 1) {
|
||||
auto right_space = reduce_streak(space_, begin, begin + n_ors, Op::Or);
|
||||
space = combine_selections(space, Op::Or, right_space);
|
||||
i += n_ors - 1;
|
||||
} else if (selects[i].op == Op::None) {
|
||||
detail::h5s_select_none(space.getId());
|
||||
} else {
|
||||
select_hyperslab(space, selects[i]);
|
||||
}
|
||||
}
|
||||
return space;
|
||||
}
|
||||
#else
|
||||
DataSpace apply_impl(const DataSpace& space_) const {
|
||||
auto space = space_.clone();
|
||||
for (const auto& sel: selects) {
|
||||
if (sel.op == Op::None) {
|
||||
detail::h5s_select_none(space.getId());
|
||||
} else {
|
||||
select_hyperslab(space, sel);
|
||||
}
|
||||
}
|
||||
return space;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Selects the Cartesian product of slices.
|
||||
///
|
||||
/// Given a one-dimensional dataset one might want to select the union of
|
||||
/// multiple, non-overlapping slices. For example,
|
||||
///
|
||||
/// using Slice = std::array<size_t, 2>;
|
||||
/// using Slices = std::vector<Slice>;
|
||||
/// auto slices = Slices{{0, 2}, {4, 10}};
|
||||
/// dset.select(ProductSet(slices);
|
||||
///
|
||||
/// to select elements `0`, `1` and `4`, ..., `9` (inclusive).
|
||||
///
|
||||
/// For a two-dimensional array one which to select the row specified above,
|
||||
/// but only columns `2`, `3` and `4`:
|
||||
///
|
||||
/// dset.select(ProductSet(slices, Slice{2, 5}));
|
||||
/// // Analogues with the roles of columns and rows reversed:
|
||||
/// dset.select(ProductSet(Slice{2, 5}, slices));
|
||||
///
|
||||
/// One can generalize once more and allow the unions of slices in both x- and
|
||||
/// y-dimension:
|
||||
///
|
||||
/// auto yslices = Slices{{1, 5}, {7, 8}};
|
||||
/// auto xslices = Slices{{0, 3}, {6, 8}};
|
||||
/// dset.select(ProductSet(yslices, xslices));
|
||||
///
|
||||
/// which selects the following from a 11x8 dataset:
|
||||
///
|
||||
/// . . . . . . . .
|
||||
/// x x x . . . x x
|
||||
/// x x x . . . x x
|
||||
/// x x x . . . x x
|
||||
/// x x x . . . x x
|
||||
/// . . . . . . . .
|
||||
/// . . . . . . . .
|
||||
/// x x x . . . x x
|
||||
/// . . . . . . . .
|
||||
/// . . . . . . . .
|
||||
/// . . . . . . . .
|
||||
///
|
||||
/// Final twist, the selection along and axis may be discrete indices, from
|
||||
/// which a vector of, possibly single-element, slices can be constructed. The
|
||||
/// corresponding types are `std::vector<size_t>` and `size_t` for multiple or
|
||||
/// just a single values. Note, looping over rows or columns one-by-one can be
|
||||
/// a very serious performance problem. In particular,
|
||||
///
|
||||
/// // Avoid:
|
||||
/// for(auto i : indices) {
|
||||
/// dset.select(i).read<double>();
|
||||
/// }
|
||||
///
|
||||
/// // Use:
|
||||
/// std::vector<size_t> tmp(indices.begin(), indices.end());
|
||||
/// dset.select(tmp).read<std::vector<double>>();
|
||||
///
|
||||
/// obvious omit the copy if `indices` already has the correct type.
|
||||
///
|
||||
/// The solution works analogous in higher dimensions. A selection `sk` along
|
||||
/// axis `k` can be interpreted as a subset `S_k` of the natural numbers. The
|
||||
/// index `i` is in `S_k` if it's selected by `sk`. The `ProductSet` of `s0`,
|
||||
/// ..., `sN` selects the Cartesian product `S_0 x ... x S_N`.
|
||||
///
|
||||
/// Note that the selections along each axis must be sorted and non-overlapping.
|
||||
///
|
||||
/// \since 3.0
|
||||
class ProductSet {
|
||||
public:
|
||||
template <class... Slices>
|
||||
explicit ProductSet(const Slices&... slices);
|
||||
|
||||
private:
|
||||
HyperSlab slab;
|
||||
std::vector<size_t> shape;
|
||||
|
||||
template <typename Derivate>
|
||||
friend class SliceTraits;
|
||||
};
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
class SliceTraits {
|
||||
public:
|
||||
///
|
||||
/// \brief Select an \p hyper_slab in the current Slice/Dataset.
|
||||
///
|
||||
/// HyperSlabs can be either regular or irregular. Irregular hyperslabs are typically generated
|
||||
/// by taking the union of regular hyperslabs. An irregular hyperslab, in general, does not fit
|
||||
/// nicely into a multi-dimensional array, but only a subset of such an array.
|
||||
///
|
||||
/// Therefore, the only memspaces supported for general hyperslabs are one-dimensional arrays.
|
||||
Selection select(const HyperSlab& hyper_slab) const;
|
||||
|
||||
///
|
||||
/// \brief Select an \p hyper_slab 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& hyper_slab, 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
|
||||
/// default to 1 in all dimensions.
|
||||
///
|
||||
/// vector offset and count have to be from the same dimension
|
||||
///
|
||||
Selection select(const std::vector<size_t>& offset,
|
||||
const std::vector<size_t>& count,
|
||||
const std::vector<size_t>& stride = {},
|
||||
const std::vector<size_t>& block = {}) const;
|
||||
|
||||
///
|
||||
/// \brief Select a set of columns in the last dimension of this dataset.
|
||||
///
|
||||
/// The column indices must be smaller than the dimension size.
|
||||
///
|
||||
Selection select(const std::vector<size_t>& columns) const;
|
||||
|
||||
///
|
||||
/// \brief Select a region in the current Slice/Dataset out of a list of elements.
|
||||
///
|
||||
Selection select(const ElementSet& elements) const;
|
||||
|
||||
///
|
||||
/// \brief Select a region consisting of a product of slices.
|
||||
///
|
||||
/// \since 3.0
|
||||
///
|
||||
Selection select(const ProductSet& product_set) const;
|
||||
|
||||
template <typename T>
|
||||
T read(const DataTransferProps& xfer_props = DataTransferProps()) const;
|
||||
|
||||
///
|
||||
/// Read the entire dataset into a buffer
|
||||
///
|
||||
/// An exception is raised is if the numbers of dimension of the buffer and
|
||||
/// of the dataset are different.
|
||||
///
|
||||
/// The array type can be a N-pointer or a N-vector. For plain pointers
|
||||
/// not dimensionality checking will be performed, it is the user's
|
||||
/// responsibility to ensure that the right amount of space has been
|
||||
/// allocated.
|
||||
template <typename T>
|
||||
void read(T& array, const DataTransferProps& xfer_props = DataTransferProps()) const;
|
||||
|
||||
///
|
||||
/// Read the entire dataset into a raw buffer
|
||||
///
|
||||
/// No dimensionality checks will be performed, it is the user's
|
||||
/// responsibility to ensure that the right amount of space has been
|
||||
/// allocated.
|
||||
/// \param array: A buffer containing enough space for the data
|
||||
/// \param mem_datatype: The type of the data in memory. This prevents deducing it from T.
|
||||
/// \param xfer_props: Data Transfer properties
|
||||
template <typename T>
|
||||
void read_raw(T* array,
|
||||
const DataType& mem_datatype,
|
||||
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 <typename T>
|
||||
void read_raw(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
|
||||
/// of the dataset are different
|
||||
///
|
||||
/// The array type can be a N-pointer or a N-vector ( e.g int** integer two
|
||||
/// dimensional array )
|
||||
template <typename T>
|
||||
void write(const T& buffer, const DataTransferProps& xfer_props = DataTransferProps());
|
||||
|
||||
///
|
||||
/// 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 datatype of `buffer`, i.e. the memory data type.
|
||||
/// \param xfer_props: The HDF5 data transfer properties, e.g. collective MPI-IO.
|
||||
template <typename T>
|
||||
void write_raw(const T* buffer,
|
||||
const DataType& mem_datatype,
|
||||
const DataTransferProps& xfer_props = DataTransferProps());
|
||||
|
||||
///
|
||||
/// 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 <typename T>
|
||||
void write_raw(const T* buffer, const DataTransferProps& xfer_props = DataTransferProps());
|
||||
|
||||
///
|
||||
/// \brief Return a `Selection` with `axes` squeezed from the memspace.
|
||||
///
|
||||
/// Returns a selection in which the memspace has been modified
|
||||
/// to not include the axes listed in `axes`.
|
||||
///
|
||||
/// Throws if any axis to be squeezes has a dimension other than `1`.
|
||||
///
|
||||
/// \since 3.0
|
||||
Selection squeezeMemSpace(const std::vector<size_t>& axes) const;
|
||||
|
||||
///
|
||||
/// \brief Return a `Selection` with a simple memspace with `dims`.
|
||||
///
|
||||
/// Returns a selection in which the memspace has been modified
|
||||
/// to be a simple dataspace with dimensions `dims`.
|
||||
///
|
||||
/// Throws if the number of elements changes.
|
||||
///
|
||||
/// \since 3.0
|
||||
Selection reshapeMemSpace(const std::vector<size_t>& dims) const;
|
||||
};
|
||||
|
||||
} // namespace HighFive
|
||||
483
include/highfive/bits/H5Slice_traits_misc.hpp
Normal file
483
include/highfive/bits/H5Slice_traits_misc.hpp
Normal file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 <algorithm>
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "h5d_wrapper.hpp"
|
||||
#include "h5s_wrapper.hpp"
|
||||
|
||||
#include "H5ReadWrite_misc.hpp"
|
||||
#include "H5Converter_misc.hpp"
|
||||
#include "squeeze.hpp"
|
||||
#include "compute_total_size.hpp"
|
||||
#include "assert_compatible_spaces.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace details {
|
||||
|
||||
// map the correct reference to the dataset depending of the layout
|
||||
// dataset -> itself
|
||||
// subselection -> parent dataset
|
||||
inline const DataSet& get_dataset(const Selection& sel) {
|
||||
return sel.getDataset();
|
||||
}
|
||||
|
||||
inline const DataSet& get_dataset(const DataSet& ds) {
|
||||
return ds;
|
||||
}
|
||||
|
||||
// map the correct memspace identifier depending of the layout
|
||||
// dataset -> entire memspace
|
||||
// selection -> resolve space id
|
||||
inline hid_t get_memspace_id(const Selection& ptr) {
|
||||
return ptr.getMemSpace().getId();
|
||||
}
|
||||
|
||||
inline hid_t get_memspace_id(const DataSet&) {
|
||||
return H5S_ALL;
|
||||
}
|
||||
} // namespace details
|
||||
|
||||
inline ElementSet::ElementSet(std::initializer_list<std::size_t> list)
|
||||
: _ids(list) {}
|
||||
|
||||
inline ElementSet::ElementSet(std::initializer_list<std::vector<std::size_t>> list)
|
||||
: ElementSet(std::vector<std::vector<std::size_t>>(list)) {}
|
||||
|
||||
inline ElementSet::ElementSet(const std::vector<std::size_t>& element_ids)
|
||||
: _ids(element_ids) {}
|
||||
|
||||
inline ElementSet::ElementSet(const std::vector<std::vector<std::size_t>>& element_ids) {
|
||||
for (const auto& vec: element_ids) {
|
||||
std::copy(vec.begin(), vec.end(), std::back_inserter(_ids));
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
class HyperCube {
|
||||
public:
|
||||
explicit HyperCube(size_t rank)
|
||||
: offset(rank)
|
||||
, count(rank) {}
|
||||
|
||||
void cross(const std::array<size_t, 2>& range, size_t axis) {
|
||||
offset[axis] = range[0];
|
||||
count[axis] = range[1] - range[0];
|
||||
}
|
||||
|
||||
RegularHyperSlab asSlab() {
|
||||
return RegularHyperSlab(offset, count);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<size_t> offset;
|
||||
std::vector<size_t> count;
|
||||
};
|
||||
|
||||
inline void build_hyper_slab(HyperSlab& slab, size_t /* axis */, HyperCube& cube) {
|
||||
slab |= cube.asSlab();
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void build_hyper_slab(HyperSlab& slab,
|
||||
size_t axis,
|
||||
HyperCube& cube,
|
||||
const std::array<size_t, 2>& slice,
|
||||
const Slices&... higher_slices) {
|
||||
cube.cross(slice, axis);
|
||||
build_hyper_slab(slab, axis + 1, cube, higher_slices...);
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void build_hyper_slab(HyperSlab& slab,
|
||||
size_t axis,
|
||||
HyperCube& cube,
|
||||
const std::vector<std::array<size_t, 2>>& slices,
|
||||
const Slices&... higher_slices) {
|
||||
for (const auto& slice: slices) {
|
||||
build_hyper_slab(slab, axis, cube, slice, higher_slices...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void build_hyper_slab(HyperSlab& slab,
|
||||
size_t axis,
|
||||
HyperCube& cube,
|
||||
const std::vector<size_t>& ids,
|
||||
const Slices&... higher_slices) {
|
||||
for (const auto& id: ids) {
|
||||
auto slice = std::array<size_t, 2>{id, id + 1};
|
||||
build_hyper_slab(slab, axis, cube, slice, higher_slices...);
|
||||
}
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void build_hyper_slab(HyperSlab& slab,
|
||||
size_t axis,
|
||||
HyperCube& cube,
|
||||
size_t id,
|
||||
const Slices&... higher_slices) {
|
||||
auto slice = std::array<size_t, 2>{id, id + 1};
|
||||
build_hyper_slab(slab, axis, cube, slice, higher_slices...);
|
||||
}
|
||||
|
||||
inline void compute_squashed_shape(size_t /* axis */, std::vector<size_t>& /* shape */) {
|
||||
// assert(axis == shape.size());
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::array<size_t, 2>& slice,
|
||||
const Slices&... higher_slices);
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::vector<size_t>& points,
|
||||
const Slices&... higher_slices);
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
size_t point,
|
||||
const Slices&... higher_slices);
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::vector<std::array<size_t, 2>>& slices,
|
||||
const Slices&... higher_slices);
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::array<size_t, 2>& slice,
|
||||
const Slices&... higher_slices) {
|
||||
shape[axis] = slice[1] - slice[0];
|
||||
compute_squashed_shape(axis + 1, shape, higher_slices...);
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::vector<size_t>& points,
|
||||
const Slices&... higher_slices) {
|
||||
shape[axis] = points.size();
|
||||
compute_squashed_shape(axis + 1, shape, higher_slices...);
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
const std::vector<std::array<size_t, 2>>& slices,
|
||||
const Slices&... higher_slices) {
|
||||
shape[axis] = 0;
|
||||
for (const auto& slice: slices) {
|
||||
shape[axis] += slice[1] - slice[0];
|
||||
}
|
||||
compute_squashed_shape(axis + 1, shape, higher_slices...);
|
||||
}
|
||||
|
||||
template <class... Slices>
|
||||
inline void compute_squashed_shape(size_t axis,
|
||||
std::vector<size_t>& shape,
|
||||
size_t /* point */,
|
||||
const Slices&... higher_slices) {
|
||||
shape[axis] = 1;
|
||||
compute_squashed_shape(axis + 1, shape, higher_slices...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class... Slices>
|
||||
inline ProductSet::ProductSet(const Slices&... slices) {
|
||||
auto rank = sizeof...(slices);
|
||||
detail::HyperCube cube(rank);
|
||||
detail::build_hyper_slab(slab, 0, cube, slices...);
|
||||
|
||||
shape = std::vector<size_t>(rank, size_t(0));
|
||||
detail::compute_squashed_shape(0, shape, slices...);
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const HyperSlab& hyper_slab,
|
||||
const DataSpace& memspace) const {
|
||||
// Note: The current limitation are that memspace must describe a
|
||||
// packed memspace.
|
||||
//
|
||||
// The reason for this is that we're unable to unpack general
|
||||
// hyperslabs when the memory is not contiguous, e.g.
|
||||
// `std::vector<std::vector<double>>`.
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
auto filespace = hyper_slab.apply(slice.getSpace());
|
||||
|
||||
return detail::make_selection(memspace, filespace, details::get_dataset(slice));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const HyperSlab& hyper_slab) const {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
auto filespace = slice.getSpace();
|
||||
filespace = hyper_slab.apply(filespace);
|
||||
|
||||
auto n_elements = detail::h5s_get_select_npoints(filespace.getId());
|
||||
auto memspace = DataSpace(std::array<size_t, 1>{size_t(n_elements)});
|
||||
|
||||
return detail::make_selection(memspace, filespace, details::get_dataset(slice));
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const std::vector<size_t>& offset,
|
||||
const std::vector<size_t>& count,
|
||||
const std::vector<size_t>& stride,
|
||||
const std::vector<size_t>& block) const {
|
||||
auto slab = HyperSlab(RegularHyperSlab(offset, count, stride, block));
|
||||
auto memspace = DataSpace(count);
|
||||
return select(slab, memspace);
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const std::vector<size_t>& columns) const {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
const DataSpace& space = slice.getSpace();
|
||||
std::vector<size_t> dims = space.getDimensions();
|
||||
|
||||
if (dims.empty()) {
|
||||
throw DataSpaceException(
|
||||
"Invalid, zero-dimensional (scalar) dataspace encountered when "
|
||||
"selecting columns; must be atleast 1-dimensional.");
|
||||
}
|
||||
|
||||
std::vector<size_t> counts = dims;
|
||||
counts.back() = 1;
|
||||
|
||||
std::vector<size_t> offsets(dims.size(), 0);
|
||||
|
||||
HyperSlab slab;
|
||||
for (const auto& column: columns) {
|
||||
offsets.back() = column;
|
||||
slab |= RegularHyperSlab(offsets, counts);
|
||||
}
|
||||
|
||||
std::vector<size_t> memdims = dims;
|
||||
memdims.back() = columns.size();
|
||||
|
||||
return select(slab, DataSpace(memdims));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const ElementSet& elements) const {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
const hsize_t* data = nullptr;
|
||||
const DataSpace space = slice.getSpace().clone();
|
||||
const std::size_t length = elements._ids.size();
|
||||
if (length % space.getNumberDimensions() != 0) {
|
||||
throw DataSpaceException(
|
||||
"Number of coordinates in elements picking "
|
||||
"should be a multiple of the dimensions.");
|
||||
}
|
||||
const std::size_t num_elements = length / space.getNumberDimensions();
|
||||
std::vector<hsize_t> raw_elements;
|
||||
|
||||
// optimised at compile time
|
||||
// switch for data conversion on 32bits platforms
|
||||
if (std::is_same<std::size_t, hsize_t>::value) {
|
||||
// `if constexpr` can't be used, thus a reinterpret_cast is needed.
|
||||
data = reinterpret_cast<const hsize_t*>(elements._ids.data());
|
||||
} else {
|
||||
raw_elements.resize(length);
|
||||
std::copy(elements._ids.begin(), elements._ids.end(), raw_elements.begin());
|
||||
data = raw_elements.data();
|
||||
}
|
||||
|
||||
detail::h5s_select_elements(space.getId(), H5S_SELECT_SET, num_elements, data);
|
||||
|
||||
return detail::make_selection(DataSpace(num_elements), space, details::get_dataset(slice));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::select(const ProductSet& product_set) const {
|
||||
return this->select(product_set.slab, DataSpace(product_set.shape));
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline T SliceTraits<Derivate>::read(const DataTransferProps& xfer_props) const {
|
||||
T array;
|
||||
read(array, xfer_props);
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::read(T& array, const DataTransferProps& xfer_props) const {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
const DataSpace& mem_space = slice.getMemSpace();
|
||||
|
||||
auto file_datatype = slice.getDataType();
|
||||
|
||||
const details::BufferInfo<T> buffer_info(
|
||||
file_datatype,
|
||||
[&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
|
||||
details::BufferInfo<T>::Operation::read);
|
||||
|
||||
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
|
||||
std::ostringstream ss;
|
||||
ss << "Impossible to read DataSet of dimensions " << mem_space.getNumberDimensions()
|
||||
<< " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
|
||||
<< buffer_info.getMaxRank() << "(max)";
|
||||
throw DataSpaceException(ss.str());
|
||||
}
|
||||
auto dims = mem_space.getDimensions();
|
||||
|
||||
auto r = details::data_converter::get_reader<T>(dims, array, file_datatype);
|
||||
read_raw(r.getPointer(), buffer_info.data_type, xfer_props);
|
||||
// re-arrange results
|
||||
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)
|
||||
detail::h5t_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer());
|
||||
#else
|
||||
// This one is deprecated since 1.12.0
|
||||
(void) detail::h5d_vlen_reclaim(t.getId(),
|
||||
mem_space.getId(),
|
||||
xfer_props.getId(),
|
||||
r.getPointer());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::read_raw(T* array,
|
||||
const DataType& mem_datatype,
|
||||
const DataTransferProps& xfer_props) const {
|
||||
static_assert(!std::is_const<T>::value,
|
||||
"read() requires a non-const structure to read data into");
|
||||
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
|
||||
detail::h5d_read(details::get_dataset(slice).getId(),
|
||||
mem_datatype.getId(),
|
||||
details::get_memspace_id(slice),
|
||||
slice.getSpace().getId(),
|
||||
xfer_props.getId(),
|
||||
static_cast<void*>(array));
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::read_raw(T* array, const DataTransferProps& xfer_props) const {
|
||||
using element_type = typename details::inspector<T>::base_type;
|
||||
const DataType& mem_datatype = create_and_check_datatype<element_type>();
|
||||
|
||||
read_raw(array, mem_datatype, xfer_props);
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::write(const T& buffer, const DataTransferProps& xfer_props) {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
const DataSpace& mem_space = slice.getMemSpace();
|
||||
auto dims = mem_space.getDimensions();
|
||||
|
||||
auto file_datatype = slice.getDataType();
|
||||
|
||||
const details::BufferInfo<T> buffer_info(
|
||||
file_datatype,
|
||||
[&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
|
||||
details::BufferInfo<T>::Operation::write);
|
||||
|
||||
if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
|
||||
std::ostringstream ss;
|
||||
ss << "Impossible to write buffer with dimensions n = " << buffer_info.getRank(buffer)
|
||||
<< "into dataset with dimensions " << details::format_vector(mem_space.getDimensions())
|
||||
<< ".";
|
||||
throw DataSpaceException(ss.str());
|
||||
}
|
||||
auto w = details::data_converter::serialize<T>(buffer, dims, file_datatype);
|
||||
write_raw(w.getPointer(), buffer_info.data_type, xfer_props);
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::write_raw(const T* buffer,
|
||||
const DataType& mem_datatype,
|
||||
const DataTransferProps& xfer_props) {
|
||||
const auto& slice = static_cast<const Derivate&>(*this);
|
||||
|
||||
detail::h5d_write(details::get_dataset(slice).getId(),
|
||||
mem_datatype.getId(),
|
||||
details::get_memspace_id(slice),
|
||||
slice.getSpace().getId(),
|
||||
xfer_props.getId(),
|
||||
static_cast<const void*>(buffer));
|
||||
}
|
||||
|
||||
|
||||
template <typename Derivate>
|
||||
template <typename T>
|
||||
inline void SliceTraits<Derivate>::write_raw(const T* buffer, const DataTransferProps& xfer_props) {
|
||||
using element_type = typename details::inspector<T>::base_type;
|
||||
const auto& mem_datatype = create_and_check_datatype<element_type>();
|
||||
|
||||
write_raw(buffer, mem_datatype, xfer_props);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
inline const DataSet& getDataSet(const Selection& selection) {
|
||||
return selection.getDataset();
|
||||
}
|
||||
|
||||
inline const DataSet& getDataSet(const DataSet& dataset) {
|
||||
return dataset;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::squeezeMemSpace(const std::vector<size_t>& axes) const {
|
||||
auto slice = static_cast<const Derivate&>(*this);
|
||||
auto mem_dims = slice.getMemSpace().getDimensions();
|
||||
auto squeezed_dims = detail::squeeze(mem_dims, axes);
|
||||
|
||||
return detail::make_selection(DataSpace(squeezed_dims),
|
||||
slice.getSpace(),
|
||||
detail::getDataSet(slice));
|
||||
}
|
||||
|
||||
template <typename Derivate>
|
||||
inline Selection SliceTraits<Derivate>::reshapeMemSpace(const std::vector<size_t>& new_dims) const {
|
||||
auto slice = static_cast<const Derivate&>(*this);
|
||||
|
||||
detail::assert_compatible_spaces(slice.getMemSpace(), new_dims);
|
||||
return detail::make_selection(DataSpace(new_dims), slice.getSpace(), detail::getDataSet(slice));
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
77
include/highfive/bits/H5Utils.hpp
Normal file
77
include/highfive/bits/H5Utils.hpp
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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
|
||||
|
||||
// internal utilities functions
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef> // __GLIBCXX__
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
|
||||
#include <H5public.h>
|
||||
|
||||
#include "../H5Exception.hpp"
|
||||
#include "H5Friends.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
namespace details {
|
||||
// converter function for hsize_t -> size_t when hsize_t != size_t
|
||||
template <typename Size>
|
||||
inline std::vector<std::size_t> to_vector_size_t(const std::vector<Size>& vec) {
|
||||
static_assert(!std::is_same<Size, std::size_t>::value, " hsize_t != size_t mandatory here");
|
||||
std::vector<size_t> res(vec.size());
|
||||
std::transform(vec.cbegin(), vec.cend(), res.begin(), [](Size e) {
|
||||
return static_cast<size_t>(e);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
// converter function for hsize_t -> size_t when size_t == hsize_t
|
||||
inline std::vector<std::size_t> to_vector_size_t(const std::vector<std::size_t>& vec) {
|
||||
return vec;
|
||||
}
|
||||
|
||||
// read name from a H5 object using the specified function
|
||||
template <typename T>
|
||||
inline std::string get_name(T fct) {
|
||||
constexpr size_t maxLength = 255;
|
||||
std::array<char, maxLength + 1> buffer;
|
||||
ssize_t retcode = fct(buffer.data(), static_cast<hsize_t>(buffer.size()));
|
||||
if (retcode < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>("Error accessing object name");
|
||||
}
|
||||
const size_t length = static_cast<std::size_t>(retcode);
|
||||
if (length <= maxLength) {
|
||||
return std::string(buffer.data(), length);
|
||||
}
|
||||
std::vector<char> bigBuffer(length + 1, 0);
|
||||
fct(bigBuffer.data(), length + 1);
|
||||
return std::string(bigBuffer.data(), length);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
inline std::string format_vector(const Container& container) {
|
||||
auto sout = std::stringstream{};
|
||||
|
||||
sout << "[ ";
|
||||
for (size_t i = 0; i < container.size(); ++i) {
|
||||
sout << container[i] << (i == container.size() - 1 ? "" : ", ");
|
||||
}
|
||||
sout << "]";
|
||||
|
||||
return sout.str();
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
46
include/highfive/bits/H5_definitions.hpp
Normal file
46
include/highfive/bits/H5_definitions.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define H5_DEPRECATED(msg) __attribute__((deprecated(#msg)))
|
||||
#elif defined(_MSC_VER)
|
||||
#define H5_DEPRECATED(msg) __declspec(deprecated(#msg))
|
||||
#else
|
||||
#pragma message("WARNING: Compiler doesn't support deprecation")
|
||||
#define H5_DEPRECATED(msg)
|
||||
#endif
|
||||
|
||||
// Forward declarations
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
enum class LinkType;
|
||||
enum class ObjectType;
|
||||
enum class PropertyType;
|
||||
|
||||
class Attribute;
|
||||
class DataSet;
|
||||
class DataSpace;
|
||||
class DataType;
|
||||
class Exception;
|
||||
class File;
|
||||
class FileDriver;
|
||||
class Group;
|
||||
class Object;
|
||||
class ObjectInfo;
|
||||
class Reference;
|
||||
class Selection;
|
||||
class SilenceHDF5;
|
||||
|
||||
template <typename T>
|
||||
class AtomicType;
|
||||
|
||||
template <typename Derivate>
|
||||
class AnnotateTraits;
|
||||
|
||||
template <typename Derivate>
|
||||
class NodeTraits;
|
||||
|
||||
template <PropertyType T>
|
||||
class PropertyList;
|
||||
|
||||
} // namespace HighFive
|
||||
29
include/highfive/bits/assert_compatible_spaces.hpp
Normal file
29
include/highfive/bits/assert_compatible_spaces.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c), 2024, BlueBrain 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)
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "../H5Exception.hpp"
|
||||
#include "../H5DataSpace.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline void assert_compatible_spaces(const DataSpace& old, const std::vector<size_t>& dims) {
|
||||
auto n_elements_old = old.getElementCount();
|
||||
auto n_elements_new = dims.empty() ? 1 : compute_total_size(dims);
|
||||
|
||||
if (n_elements_old != n_elements_new) {
|
||||
throw Exception("Invalid parameter `new_dims` number of elements differ: " +
|
||||
std::to_string(n_elements_old) + " (old) vs. " +
|
||||
std::to_string(n_elements_new) + " (new)");
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
14
include/highfive/bits/compute_total_size.hpp
Normal file
14
include/highfive/bits/compute_total_size.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <numeric>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
inline size_t compute_total_size(const std::vector<size_t>& dims) {
|
||||
return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies<size_t>());
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
31
include/highfive/bits/convert_size_vector.hpp
Normal file
31
include/highfive/bits/convert_size_vector.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
* Copyright (c), 2017-2024, BlueBrain 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)
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
template <class To, class From, class It = From const*>
|
||||
inline std::vector<To> convertSizeVector(const It& begin, const It& end) {
|
||||
std::vector<To> to(static_cast<size_t>(end - begin));
|
||||
std::copy(begin, end, to.begin());
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
template <class To, class From>
|
||||
inline std::vector<To> convertSizeVector(const std::vector<From>& from) {
|
||||
return convertSizeVector<To, From>(from.cbegin(), from.cend());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
19
include/highfive/bits/h5_wrapper.hpp
Normal file
19
include/highfive/bits/h5_wrapper.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#include <H5public.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
inline void h5_free_memory(void* mem) {
|
||||
if (H5free_memory(mem) < 0) {
|
||||
throw DataTypeException("Could not free memory allocated by HDF5");
|
||||
}
|
||||
}
|
||||
|
||||
namespace nothrow {
|
||||
inline herr_t h5_free_memory(void* mem) {
|
||||
return H5free_memory(mem);
|
||||
}
|
||||
} // namespace nothrow
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
131
include/highfive/bits/h5a_wrapper.hpp
Normal file
131
include/highfive/bits/h5a_wrapper.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Apublic.h>
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline hid_t h5a_create2(hid_t loc_id,
|
||||
char const* const attr_name,
|
||||
hid_t type_id,
|
||||
hid_t space_id,
|
||||
hid_t acpl_id,
|
||||
hid_t aapl_id) {
|
||||
auto attr_id = H5Acreate2(loc_id, attr_name, type_id, space_id, acpl_id, aapl_id);
|
||||
if (attr_id < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to create the attribute \"") + attr_name + "\":");
|
||||
}
|
||||
|
||||
return attr_id;
|
||||
}
|
||||
|
||||
inline void h5a_delete(hid_t loc_id, char const* const attr_name) {
|
||||
if (H5Adelete(loc_id, attr_name) < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to delete attribute \"") + attr_name + "\":");
|
||||
}
|
||||
}
|
||||
|
||||
inline hid_t h5a_open(hid_t loc_id, char const* const attr_name, hid_t aapl_id) {
|
||||
const auto attr_id = H5Aopen(loc_id, attr_name, aapl_id);
|
||||
if (attr_id < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to open the attribute \"") + attr_name + "\":");
|
||||
}
|
||||
|
||||
return attr_id;
|
||||
}
|
||||
|
||||
|
||||
inline int h5a_get_num_attrs(hid_t loc_id) {
|
||||
int res = H5Aget_num_attrs(loc_id);
|
||||
if (res < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to count attributes in existing group or file"));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
inline void h5a_iterate2(hid_t loc_id,
|
||||
H5_index_t idx_type,
|
||||
H5_iter_order_t order,
|
||||
hsize_t* idx,
|
||||
H5A_operator2_t op,
|
||||
void* op_data) {
|
||||
if (H5Aiterate2(loc_id, idx_type, order, idx, op, op_data) < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(std::string("Failed H5Aiterate2."));
|
||||
}
|
||||
}
|
||||
|
||||
inline int h5a_exists(hid_t obj_id, char const* const attr_name) {
|
||||
int res = H5Aexists(obj_id, attr_name);
|
||||
if (res < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to check for attribute in group"));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
inline ssize_t h5a_get_name(hid_t attr_id, size_t buf_size, char* buf) {
|
||||
ssize_t name_length = H5Aget_name(attr_id, buf_size, buf);
|
||||
if (name_length < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to get name of attribute"));
|
||||
}
|
||||
|
||||
return name_length;
|
||||
}
|
||||
|
||||
|
||||
inline hid_t h5a_get_space(hid_t attr_id) {
|
||||
hid_t attr = H5Aget_space(attr_id);
|
||||
if (attr < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to get dataspace of attribute"));
|
||||
}
|
||||
|
||||
return attr;
|
||||
}
|
||||
|
||||
inline hsize_t h5a_get_storage_size(hid_t attr_id) {
|
||||
// Docs:
|
||||
// Returns the amount of storage size allocated for the attribute;
|
||||
// otherwise returns 0 (zero).
|
||||
return H5Aget_storage_size(attr_id);
|
||||
}
|
||||
|
||||
inline hid_t h5a_get_type(hid_t attr_id) {
|
||||
hid_t type_id = H5Aget_type(attr_id);
|
||||
if (type_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(
|
||||
std::string("Unable to get datatype of attribute"));
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
inline herr_t h5a_read(hid_t attr_id, hid_t type_id, void* buf) {
|
||||
herr_t err = H5Aread(attr_id, type_id, buf);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(std::string("Unable to read attribute"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5a_write(hid_t attr_id, hid_t type_id, void const* buf) {
|
||||
herr_t err = H5Awrite(attr_id, type_id, buf);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<AttributeException>(std::string("Unable to write attribute"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
125
include/highfive/bits/h5d_wrapper.hpp
Normal file
125
include/highfive/bits/h5d_wrapper.hpp
Normal file
@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Dpublic.h>
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
|
||||
#if !H5_VERSION_GE(1, 12, 0)
|
||||
inline herr_t h5d_vlen_reclaim(hid_t type_id, hid_t space_id, hid_t dxpl_id, void* buf) {
|
||||
herr_t err = H5Dvlen_reclaim(type_id, space_id, dxpl_id, buf);
|
||||
if (err < 0) {
|
||||
throw DataSetException("Failed to reclaim HDF5 internal memory");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline hsize_t h5d_get_storage_size(hid_t dset_id) {
|
||||
// Docs:
|
||||
// H5Dget_storage_size() does not differentiate between 0 (zero), the
|
||||
// value returned for the storage size of a dataset with no stored values,
|
||||
// and 0 (zero), the value returned to indicate an error.
|
||||
return H5Dget_storage_size(dset_id);
|
||||
}
|
||||
|
||||
inline hid_t h5d_get_space(hid_t dset_id) {
|
||||
hid_t dset = H5Dget_space(dset_id);
|
||||
if (dset == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(
|
||||
std::string("Unable to get dataspace of the dataset"));
|
||||
}
|
||||
|
||||
return dset;
|
||||
}
|
||||
|
||||
inline hid_t h5d_get_type(hid_t dset_id) {
|
||||
hid_t type_id = H5Dget_type(dset_id);
|
||||
if (type_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(
|
||||
std::string("Unable to get datatype of the dataset"));
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
inline herr_t h5d_read(hid_t dset_id,
|
||||
hid_t mem_type_id,
|
||||
hid_t mem_space_id,
|
||||
hid_t file_space_id,
|
||||
hid_t dxpl_id,
|
||||
void* buf) {
|
||||
herr_t err = H5Dread(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(std::string("Unable to read the dataset"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5d_write(hid_t dset_id,
|
||||
hid_t mem_type_id,
|
||||
hid_t mem_space_id,
|
||||
hid_t file_space_id,
|
||||
hid_t dxpl_id,
|
||||
const void* buf) {
|
||||
herr_t err = H5Dwrite(dset_id, mem_type_id, mem_space_id, file_space_id, dxpl_id, buf);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(std::string("Unable to write the dataset"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline haddr_t h5d_get_offset(hid_t dset_id) {
|
||||
uint64_t addr = H5Dget_offset(dset_id);
|
||||
if (addr == HADDR_UNDEF) {
|
||||
HDF5ErrMapper::ToException<DataSetException>("Cannot get offset of DataSet.");
|
||||
}
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
inline herr_t h5d_set_extent(hid_t dset_id, const hsize_t size[]) {
|
||||
herr_t err = H5Dset_extent(dset_id, size);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>("Could not resize dataset.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hid_t h5d_create2(hid_t loc_id,
|
||||
const char* name,
|
||||
hid_t type_id,
|
||||
hid_t space_id,
|
||||
hid_t lcpl_id,
|
||||
hid_t dcpl_id,
|
||||
hid_t dapl_id) {
|
||||
hid_t dataset_id = H5Dcreate2(loc_id, name, type_id, space_id, lcpl_id, dcpl_id, dapl_id);
|
||||
|
||||
if (dataset_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(
|
||||
std::string("Failed to create the dataset \"") + name + "\":");
|
||||
}
|
||||
|
||||
return dataset_id;
|
||||
}
|
||||
|
||||
inline hid_t h5d_open2(hid_t loc_id, const char* name, hid_t dapl_id) {
|
||||
hid_t dataset_id = H5Dopen2(loc_id, name, dapl_id);
|
||||
|
||||
if (dataset_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(std::string("Unable to open the dataset \"") +
|
||||
name + "\":");
|
||||
}
|
||||
|
||||
return dataset_id;
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
39
include/highfive/bits/h5e_wrapper.hpp
Normal file
39
include/highfive/bits/h5e_wrapper.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Epublic.h>
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
namespace nothrow {
|
||||
|
||||
|
||||
inline void h5e_get_auto2(hid_t estack_id, H5E_auto2_t* func, void** client_data) {
|
||||
H5Eget_auto2(estack_id, func, client_data);
|
||||
}
|
||||
|
||||
inline void h5e_set_auto2(hid_t estack_id, H5E_auto2_t func, void* client_data) {
|
||||
H5Eset_auto2(estack_id, func, client_data);
|
||||
}
|
||||
|
||||
inline char* h5e_get_major(H5E_major_t maj) {
|
||||
return H5Eget_major(maj);
|
||||
}
|
||||
|
||||
inline char* h5e_get_minor(H5E_minor_t min) {
|
||||
return H5Eget_minor(min);
|
||||
}
|
||||
|
||||
inline herr_t h5e_walk2(hid_t err_stack,
|
||||
H5E_direction_t direction,
|
||||
H5E_walk2_t func,
|
||||
void* client_data) {
|
||||
return H5Ewalk2(err_stack, direction, func, client_data);
|
||||
}
|
||||
|
||||
inline herr_t h5e_clear2(hid_t err_stack) {
|
||||
return H5Eclear2(err_stack);
|
||||
}
|
||||
|
||||
|
||||
} // namespace nothrow
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
58
include/highfive/bits/h5f_wrapper.hpp
Normal file
58
include/highfive/bits/h5f_wrapper.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Fpublic.h>
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
namespace nothrow {
|
||||
inline hid_t h5f_open(const char* filename, unsigned flags, hid_t fapl_id) {
|
||||
return H5Fopen(filename, flags, fapl_id);
|
||||
}
|
||||
} // namespace nothrow
|
||||
|
||||
inline hid_t h5f_create(const char* filename, unsigned flags, hid_t fcpl_id, hid_t fapl_id) {
|
||||
hid_t file_id = H5Fcreate(filename, flags, fcpl_id, fapl_id);
|
||||
|
||||
if (file_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<FileException>(std::string("Failed to create file ") + filename);
|
||||
}
|
||||
return file_id;
|
||||
}
|
||||
|
||||
inline ssize_t h5f_get_name(hid_t obj_id, char* name, size_t size) {
|
||||
ssize_t nread = H5Fget_name(obj_id, name, size);
|
||||
if (nread < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>(std::string("Failed to get file from id"));
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
inline herr_t h5f_flush(hid_t object_id, H5F_scope_t scope) {
|
||||
herr_t err = H5Fflush(object_id, scope);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>(std::string("Failed to flush file"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5f_get_filesize(hid_t file_id, hsize_t* size) {
|
||||
herr_t err = H5Fget_filesize(file_id, size);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>(std::string("Unable to retrieve size of file"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hssize_t h5f_get_freespace(hid_t file_id) {
|
||||
hssize_t free_space = H5Fget_freespace(file_id);
|
||||
if (free_space < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>(
|
||||
std::string("Unable to retrieve unused space of file "));
|
||||
}
|
||||
return free_space;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
46
include/highfive/bits/h5g_wrapper.hpp
Normal file
46
include/highfive/bits/h5g_wrapper.hpp
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Dpublic.h>
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
#include <highfive/H5Exception.hpp>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline hid_t h5g_create2(hid_t loc_id,
|
||||
const char* name,
|
||||
hid_t lcpl_id,
|
||||
hid_t gcpl_id,
|
||||
hid_t gapl_id) {
|
||||
hid_t group_id = H5Gcreate2(loc_id, name, lcpl_id, gcpl_id, gapl_id);
|
||||
if (group_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to create the group \"") +
|
||||
name + "\":");
|
||||
}
|
||||
|
||||
return group_id;
|
||||
}
|
||||
|
||||
inline hid_t h5g_open2(hid_t loc_id, const char* name, hid_t gapl_id) {
|
||||
hid_t group_id = H5Gopen2(loc_id, name, gapl_id);
|
||||
if (group_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to open the group \"") +
|
||||
name + "\":");
|
||||
}
|
||||
return group_id;
|
||||
}
|
||||
|
||||
inline herr_t h5g_get_num_objs(hid_t loc_id, hsize_t* num_objs) {
|
||||
herr_t err = H5Gget_num_objs(loc_id, num_objs);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(
|
||||
std::string("Unable to count objects in existing group or file"));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
79
include/highfive/bits/h5i_wrapper.hpp
Normal file
79
include/highfive/bits/h5i_wrapper.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
inline int h5i_inc_ref(hid_t id) {
|
||||
auto count = H5Iinc_ref(id);
|
||||
|
||||
if (count < 0) {
|
||||
throw ObjectException("Failed to increase reference count of HID");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
namespace nothrow {
|
||||
|
||||
inline int h5i_dec_ref(hid_t id) {
|
||||
return H5Idec_ref(id);
|
||||
}
|
||||
|
||||
} // namespace nothrow
|
||||
|
||||
inline int h5i_dec_ref(hid_t id) {
|
||||
int count = H5Idec_ref(id);
|
||||
if (count < 0) {
|
||||
throw ObjectException("Failed to decrease reference count of HID");
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
namespace nothrow {
|
||||
inline htri_t h5i_is_valid(hid_t id) {
|
||||
return H5Iis_valid(id);
|
||||
}
|
||||
|
||||
} // namespace nothrow
|
||||
|
||||
inline htri_t h5i_is_valid(hid_t id) {
|
||||
htri_t tri = H5Iis_valid(id);
|
||||
if (tri < 0) {
|
||||
throw ObjectException("Failed to check if HID is valid");
|
||||
}
|
||||
|
||||
return tri;
|
||||
}
|
||||
|
||||
inline H5I_type_t h5i_get_type(hid_t id) {
|
||||
H5I_type_t type = H5Iget_type(id);
|
||||
if (type == H5I_BADID) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Failed to get type of HID");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
template <class Exception>
|
||||
inline hid_t h5i_get_file_id(hid_t id) {
|
||||
hid_t file_id = H5Iget_file_id(id);
|
||||
if (file_id < 0) {
|
||||
HDF5ErrMapper::ToException<Exception>("Failed not obtain file HID of object");
|
||||
}
|
||||
|
||||
return file_id;
|
||||
}
|
||||
|
||||
inline ssize_t h5i_get_name(hid_t id, char* name, size_t size) {
|
||||
ssize_t n_chars = H5Iget_name(id, name, size);
|
||||
if (n_chars < 0) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Failed to get name of HID.");
|
||||
}
|
||||
|
||||
return n_chars;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
132
include/highfive/bits/h5l_wrapper.hpp
Normal file
132
include/highfive/bits/h5l_wrapper.hpp
Normal file
@ -0,0 +1,132 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Lpublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline herr_t h5l_create_external(const char* file_name,
|
||||
const char* obj_name,
|
||||
hid_t link_loc_id,
|
||||
const char* link_name,
|
||||
hid_t lcpl_id,
|
||||
hid_t lapl_id) {
|
||||
herr_t err = H5Lcreate_external(file_name, obj_name, link_loc_id, link_name, lcpl_id, lapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to create external link: "));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5l_create_soft(const char* link_target,
|
||||
hid_t link_loc_id,
|
||||
const char* link_name,
|
||||
hid_t lcpl_id,
|
||||
hid_t lapl_id) {
|
||||
herr_t err = H5Lcreate_soft(link_target, link_loc_id, link_name, lcpl_id, lapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to create soft link: "));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5l_create_hard(hid_t cur_loc,
|
||||
const char* cur_name,
|
||||
hid_t dst_loc,
|
||||
const char* dst_name,
|
||||
hid_t lcpl_id,
|
||||
hid_t lapl_id) {
|
||||
herr_t err = H5Lcreate_hard(cur_loc, cur_name, dst_loc, dst_name, lcpl_id, lapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to create hard link: "));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5l_get_info(hid_t loc_id, const char* name, H5L_info_t* linfo, hid_t lapl_id) {
|
||||
herr_t err = H5Lget_info(loc_id, name, linfo, lapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to obtain info for link "));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5l_delete(hid_t loc_id, const char* name, hid_t lapl_id) {
|
||||
herr_t err = H5Ldelete(loc_id, name, lapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Invalid name for unlink() "));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline htri_t h5l_exists(hid_t loc_id, const char* name, hid_t lapl_id) {
|
||||
htri_t tri = H5Lexists(loc_id, name, lapl_id);
|
||||
if (tri < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>("Invalid link for exist()");
|
||||
}
|
||||
|
||||
return tri;
|
||||
}
|
||||
|
||||
namespace nothrow {
|
||||
|
||||
inline htri_t h5l_exists(hid_t loc_id, const char* name, hid_t lapl_id) {
|
||||
return H5Lexists(loc_id, name, lapl_id);
|
||||
}
|
||||
|
||||
} // namespace nothrow
|
||||
|
||||
inline herr_t h5l_iterate(hid_t grp_id,
|
||||
H5_index_t idx_type,
|
||||
H5_iter_order_t order,
|
||||
hsize_t* idx,
|
||||
H5L_iterate_t op,
|
||||
void* op_data) {
|
||||
herr_t err = H5Literate(grp_id, idx_type, order, idx, op, op_data);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to list objects in group"));
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5l_move(hid_t src_loc,
|
||||
const char* src_name,
|
||||
hid_t dst_loc,
|
||||
const char* dst_name,
|
||||
hid_t lcpl_id,
|
||||
hid_t lapl_id) {
|
||||
herr_t err = H5Lmove(src_loc, src_name, dst_loc, dst_name, lcpl_id, lapl_id);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to move link to \"") +
|
||||
dst_name + "\":");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline ssize_t h5l_get_name_by_idx(hid_t loc_id,
|
||||
const char* group_name,
|
||||
H5_index_t idx_type,
|
||||
H5_iter_order_t order,
|
||||
hsize_t n,
|
||||
char* name,
|
||||
size_t size,
|
||||
hid_t lapl_id) {
|
||||
ssize_t n_chars =
|
||||
H5Lget_name_by_idx(loc_id, group_name, idx_type, order, n, name, size, lapl_id);
|
||||
|
||||
if (n_chars < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(
|
||||
std::string("Unable to obtain link name from index."));
|
||||
}
|
||||
|
||||
return n_chars;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
66
include/highfive/bits/h5o_wrapper.hpp
Normal file
66
include/highfive/bits/h5o_wrapper.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Opublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline hid_t h5o_open(hid_t loc_id, const char* name, hid_t lapl_id) {
|
||||
hid_t hid = H5Oopen(loc_id, name, lapl_id);
|
||||
if (hid < 0) {
|
||||
HDF5ErrMapper::ToException<GroupException>(std::string("Unable to open \"") + name + "\":");
|
||||
}
|
||||
|
||||
return hid;
|
||||
}
|
||||
|
||||
inline herr_t h5o_close(hid_t id) {
|
||||
herr_t err = H5Oclose(id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Unable to close object.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if H5O_info_t_vers >= 1
|
||||
using h5o_info1_t = H5O_info1_t;
|
||||
#else
|
||||
using h5o_info1_t = H5O_info_t;
|
||||
#endif
|
||||
|
||||
inline herr_t h5o_get_info1(hid_t loc_id, h5o_info1_t* info) {
|
||||
#if H5Oget_info_vers >= 1
|
||||
herr_t err = H5Oget_info1(loc_id, info);
|
||||
#else
|
||||
herr_t err = H5Oget_info(loc_id, info);
|
||||
#endif
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Unable to obtain info for object");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 3)
|
||||
inline herr_t h5o_get_info2(hid_t loc_id, h5o_info1_t* info, unsigned fields) {
|
||||
herr_t err = H5Oget_info2(loc_id, info, fields);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Unable to obtain info for object");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if H5_VERSION_GE(1, 12, 0)
|
||||
inline herr_t h5o_get_info3(hid_t loc_id, H5O_info2_t* info, unsigned fields) {
|
||||
herr_t err = H5Oget_info3(loc_id, info, fields);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<ObjectException>("Unable to obtain info for object");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
376
include/highfive/bits/h5p_wrapper.hpp
Normal file
376
include/highfive/bits/h5p_wrapper.hpp
Normal file
@ -0,0 +1,376 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
#include <H5Ppublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
inline hid_t h5p_create(hid_t cls_id) {
|
||||
hid_t plist_id = H5Pcreate(cls_id);
|
||||
if (plist_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Failed to create property list");
|
||||
}
|
||||
|
||||
return plist_id;
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 1)
|
||||
inline herr_t h5p_set_file_space_strategy(hid_t plist_id,
|
||||
H5F_fspace_strategy_t strategy,
|
||||
hbool_t persist,
|
||||
hsize_t threshold) {
|
||||
herr_t err = H5Pset_file_space_strategy(plist_id, strategy, persist, threshold);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to get file space strategy");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_file_space_strategy(hid_t plist_id,
|
||||
H5F_fspace_strategy_t* strategy,
|
||||
hbool_t* persist,
|
||||
hsize_t* threshold) {
|
||||
herr_t err = H5Pget_file_space_strategy(plist_id, strategy, persist, threshold);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error getting file space strategy.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_file_space_page_size(hid_t plist_id, hsize_t fsp_size) {
|
||||
herr_t err = H5Pset_file_space_page_size(plist_id, fsp_size);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting file space page size.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_file_space_page_size(hid_t plist_id, hsize_t* fsp_size) {
|
||||
herr_t err = H5Pget_file_space_page_size(plist_id, fsp_size);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to get file space page size");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifndef H5_HAVE_PARALLEL
|
||||
inline herr_t h5p_get_page_buffer_size(hid_t plist_id,
|
||||
size_t* buf_size,
|
||||
unsigned* min_meta_perc,
|
||||
unsigned* min_raw_perc) {
|
||||
herr_t err = H5Pget_page_buffer_size(plist_id, buf_size, min_meta_perc, min_raw_perc);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting page buffer size.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_page_buffer_size(hid_t plist_id,
|
||||
size_t buf_size,
|
||||
unsigned min_meta_per,
|
||||
unsigned min_raw_per) {
|
||||
herr_t err = H5Pset_page_buffer_size(plist_id, buf_size, min_meta_per, min_raw_per);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting page buffer size.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
inline herr_t h5p_set_fapl_mpio(hid_t fapl_id, MPI_Comm comm, MPI_Info info) {
|
||||
herr_t err = H5Pset_fapl_mpio(fapl_id, comm, info);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>("Unable to set-up MPIO Driver configuration");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 0)
|
||||
inline herr_t h5p_set_all_coll_metadata_ops(hid_t plist_id, hbool_t is_collective) {
|
||||
herr_t err = H5Pset_all_coll_metadata_ops(plist_id, is_collective);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>("Unable to request collective metadata reads");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_all_coll_metadata_ops(hid_t plist_id, hbool_t* is_collective) {
|
||||
herr_t err = H5Pget_all_coll_metadata_ops(plist_id, is_collective);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error loading MPI metadata read.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_coll_metadata_write(hid_t plist_id, hbool_t is_collective) {
|
||||
herr_t err = H5Pset_coll_metadata_write(plist_id, is_collective);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<FileException>("Unable to request collective metadata writes");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_coll_metadata_write(hid_t plist_id, hbool_t* is_collective) {
|
||||
herr_t err = H5Pget_coll_metadata_write(plist_id, is_collective);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error loading MPI metadata write.");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline herr_t h5p_get_libver_bounds(hid_t plist_id, H5F_libver_t* low, H5F_libver_t* high) {
|
||||
herr_t err = H5Pget_libver_bounds(plist_id, low, high);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to access file version bounds");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_libver_bounds(hid_t plist_id, H5F_libver_t low, H5F_libver_t high) {
|
||||
herr_t err = H5Pset_libver_bounds(plist_id, low, high);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting file version bounds");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_meta_block_size(hid_t fapl_id, hsize_t* size) {
|
||||
herr_t err = H5Pget_meta_block_size(fapl_id, size);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to access file metadata block size");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_meta_block_size(hid_t fapl_id, hsize_t size) {
|
||||
herr_t err = H5Pset_meta_block_size(fapl_id, size);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting metadata block size");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_est_link_info(hid_t plist_id,
|
||||
unsigned est_num_entries,
|
||||
unsigned est_name_len) {
|
||||
herr_t err = H5Pset_est_link_info(plist_id, est_num_entries, est_name_len);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting estimated link info");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_est_link_info(hid_t plist_id,
|
||||
unsigned* est_num_entries,
|
||||
unsigned* est_name_len) {
|
||||
herr_t err = H5Pget_est_link_info(plist_id, est_num_entries, est_name_len);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Unable to access group link size property");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_chunk(hid_t plist_id, int ndims, const hsize_t dim[]) {
|
||||
herr_t err = H5Pset_chunk(plist_id, ndims, dim);
|
||||
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting chunk property");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline int h5p_get_chunk(hid_t plist_id, int max_ndims, hsize_t dim[]) {
|
||||
int chunk_dims = H5Pget_chunk(plist_id, max_ndims, dim);
|
||||
if (chunk_dims < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error getting chunk size");
|
||||
}
|
||||
return chunk_dims;
|
||||
}
|
||||
|
||||
inline htri_t h5z_filter_avail(H5Z_filter_t id) {
|
||||
htri_t tri = H5Zfilter_avail(id);
|
||||
if (tri < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error checking filter availability");
|
||||
}
|
||||
return tri;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_deflate(hid_t plist_id, unsigned level) {
|
||||
herr_t err = H5Pset_deflate(plist_id, level);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting deflate property");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_szip(hid_t plist_id, unsigned options_mask, unsigned pixels_per_block) {
|
||||
herr_t err = H5Pset_szip(plist_id, options_mask, pixels_per_block);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting szip property");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_shuffle(hid_t plist_id) {
|
||||
herr_t err = H5Pset_shuffle(plist_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting shuffle property");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_alloc_time(hid_t plist_id, H5D_alloc_time_t* alloc_time) {
|
||||
herr_t err = H5Pget_alloc_time(plist_id, alloc_time);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error getting allocation time");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_alloc_time(hid_t plist_id, H5D_alloc_time_t alloc_time) {
|
||||
herr_t err = H5Pset_alloc_time(plist_id, alloc_time);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting allocation time");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_chunk_cache(hid_t dapl_id,
|
||||
size_t* rdcc_nslots,
|
||||
size_t* rdcc_nbytes,
|
||||
double* rdcc_w0) {
|
||||
herr_t err = H5Pget_chunk_cache(dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error getting dataset cache parameters");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_chunk_cache(hid_t dapl_id,
|
||||
size_t rdcc_nslots,
|
||||
size_t rdcc_nbytes,
|
||||
double rdcc_w0) {
|
||||
herr_t err = H5Pset_chunk_cache(dapl_id, rdcc_nslots, rdcc_nbytes, rdcc_w0);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting dataset cache parameters");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_create_intermediate_group(hid_t plist_id, unsigned crt_intmd) {
|
||||
herr_t err = H5Pset_create_intermediate_group(plist_id, crt_intmd);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>(
|
||||
"Error setting property for create intermediate groups");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_create_intermediate_group(hid_t plist_id, unsigned* crt_intmd) {
|
||||
herr_t err = H5Pget_create_intermediate_group(plist_id, crt_intmd);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>(
|
||||
"Error getting property for create intermediate groups");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#ifdef H5_HAVE_PARALLEL
|
||||
inline herr_t h5p_set_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t xfer_mode) {
|
||||
herr_t err = H5Pset_dxpl_mpio(dxpl_id, xfer_mode);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting H5Pset_dxpl_mpio.");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_dxpl_mpio(hid_t dxpl_id, H5FD_mpio_xfer_t* xfer_mode) {
|
||||
herr_t err = H5Pget_dxpl_mpio(dxpl_id, xfer_mode);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error getting H5Pset_dxpl_mpio.");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_mpio_no_collective_cause(hid_t plist_id,
|
||||
uint32_t* local_no_collective_cause,
|
||||
uint32_t* global_no_collective_cause) {
|
||||
herr_t err = H5Pget_mpio_no_collective_cause(plist_id,
|
||||
local_no_collective_cause,
|
||||
global_no_collective_cause);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Failed to check mpio_no_collective_cause.");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline herr_t h5p_set_link_creation_order(hid_t plist_id, unsigned crt_order_flags) {
|
||||
herr_t err = H5Pset_link_creation_order(plist_id, crt_order_flags);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>("Error setting LinkCreationOrder.");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_link_creation_order(hid_t plist_id, unsigned* crt_order_flags) {
|
||||
herr_t err = H5Pget_link_creation_order(plist_id, crt_order_flags);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>(
|
||||
"Error getting property for link creation order");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_get_attr_phase_change(hid_t plist_id,
|
||||
unsigned* max_compact,
|
||||
unsigned* min_dense) {
|
||||
herr_t err = H5Pget_attr_phase_change(plist_id, max_compact, min_dense);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>(
|
||||
"Error getting property for attribute phase change");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5p_set_attr_phase_change(hid_t plist_id, unsigned max_compact, unsigned min_dense) {
|
||||
herr_t err = H5Pset_attr_phase_change(plist_id, max_compact, min_dense);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<PropertyException>(
|
||||
"Error getting property for attribute phase change");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
42
include/highfive/bits/h5r_wrapper.hpp
Normal file
42
include/highfive/bits/h5r_wrapper.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Rpublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
inline herr_t h5r_create(void* ref,
|
||||
hid_t loc_id,
|
||||
const char* name,
|
||||
H5R_type_t ref_type,
|
||||
hid_t space_id) {
|
||||
herr_t err = H5Rcreate(ref, loc_id, name, ref_type, space_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<ReferenceException>(
|
||||
std::string("Unable to create the reference for \"") + name + "\":");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if (H5Rdereference_vers == 2)
|
||||
inline hid_t h5r_dereference(hid_t obj_id, hid_t oapl_id, H5R_type_t ref_type, const void* ref) {
|
||||
hid_t hid = H5Rdereference(obj_id, oapl_id, ref_type, ref);
|
||||
if (hid < 0) {
|
||||
HDF5ErrMapper::ToException<ReferenceException>("Unable to dereference.");
|
||||
}
|
||||
|
||||
return hid;
|
||||
}
|
||||
#else
|
||||
inline hid_t h5r_dereference(hid_t dataset, H5R_type_t ref_type, const void* ref) {
|
||||
hid_t hid = H5Rdereference(dataset, ref_type, ref);
|
||||
if (hid < 0) {
|
||||
HDF5ErrMapper::ToException<ReferenceException>("Unable to dereference.");
|
||||
}
|
||||
|
||||
return hid;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
136
include/highfive/bits/h5s_wrapper.hpp
Normal file
136
include/highfive/bits/h5s_wrapper.hpp
Normal file
@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
#include <H5Spublic.h>
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline hid_t h5s_create_simple(int rank, const hsize_t dims[], const hsize_t maxdims[]) {
|
||||
hid_t space_id = H5Screate_simple(rank, dims, maxdims);
|
||||
if (space_id == H5I_INVALID_HID) {
|
||||
throw DataSpaceException("Unable to create simple dataspace");
|
||||
}
|
||||
|
||||
return space_id;
|
||||
}
|
||||
|
||||
inline hid_t h5s_create(H5S_class_t type) {
|
||||
hid_t space_id = H5Screate(type);
|
||||
|
||||
if (space_id == H5I_INVALID_HID) {
|
||||
throw DataSpaceException("Unable to create dataspace");
|
||||
}
|
||||
|
||||
return space_id;
|
||||
}
|
||||
|
||||
inline hid_t h5s_copy(hid_t space_id) {
|
||||
hid_t copy_id = H5Scopy(space_id);
|
||||
|
||||
if (copy_id < 0) {
|
||||
throw DataSpaceException("Unable to copy dataspace");
|
||||
}
|
||||
|
||||
return copy_id;
|
||||
}
|
||||
|
||||
inline herr_t h5s_select_none(hid_t spaceid) {
|
||||
herr_t err = H5Sselect_none(spaceid);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to select None space");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5s_select_hyperslab(hid_t space_id,
|
||||
H5S_seloper_t op,
|
||||
const hsize_t start[],
|
||||
const hsize_t stride[],
|
||||
const hsize_t count[],
|
||||
const hsize_t block[]) {
|
||||
herr_t err = H5Sselect_hyperslab(space_id, op, start, stride, count, block);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to select hyperslab");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hssize_t h5s_get_select_npoints(hid_t spaceid) {
|
||||
hssize_t n_points = H5Sget_select_npoints(spaceid);
|
||||
if (n_points < 0) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>(
|
||||
"Unable to get number of points in selection");
|
||||
}
|
||||
return n_points;
|
||||
}
|
||||
|
||||
inline herr_t h5s_select_elements(hid_t space_id,
|
||||
H5S_seloper_t op,
|
||||
size_t num_elem,
|
||||
const hsize_t* coord) {
|
||||
herr_t err = H5Sselect_elements(space_id, op, num_elem, coord);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to select elements");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline int h5s_get_simple_extent_ndims(hid_t space_id) {
|
||||
int ndim = H5Sget_simple_extent_ndims(space_id);
|
||||
if (ndim < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(
|
||||
"Unable to get number of dimensions of dataspace");
|
||||
}
|
||||
return ndim;
|
||||
}
|
||||
|
||||
inline herr_t h5s_get_simple_extent_dims(hid_t space_id, hsize_t dims[], hsize_t maxdims[]) {
|
||||
herr_t err = H5Sget_simple_extent_dims(space_id, dims, maxdims);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>("Unable to get dimensions of dataspace");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hssize_t h5s_get_simple_extent_npoints(hid_t space_id) {
|
||||
hssize_t nelements = H5Sget_simple_extent_npoints(space_id);
|
||||
if (nelements < 0) {
|
||||
HDF5ErrMapper::ToException<DataSetException>(
|
||||
"Unable to get number of elements in dataspace");
|
||||
}
|
||||
|
||||
return nelements;
|
||||
}
|
||||
|
||||
inline H5S_class_t h5s_get_simple_extent_type(hid_t space_id) {
|
||||
H5S_class_t cls = H5Sget_simple_extent_type(space_id);
|
||||
if (cls == H5S_NO_CLASS) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to get class of simple dataspace.");
|
||||
}
|
||||
|
||||
return cls;
|
||||
}
|
||||
|
||||
inline H5S_sel_type h5s_get_select_type(hid_t space_id) {
|
||||
H5S_sel_type type = H5Sget_select_type(space_id);
|
||||
if (type < 0) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to get type of selection.");
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 10, 6)
|
||||
inline hid_t h5s_combine_select(hid_t space1_id, H5S_seloper_t op, hid_t space2_id) {
|
||||
auto space_id = H5Scombine_select(space1_id, op, space2_id);
|
||||
if (space_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataSpaceException>("Unable to combine two selections.");
|
||||
}
|
||||
|
||||
return space_id;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
230
include/highfive/bits/h5t_wrapper.hpp
Normal file
230
include/highfive/bits/h5t_wrapper.hpp
Normal file
@ -0,0 +1,230 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Ipublic.h>
|
||||
#include <H5Tpublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
inline hid_t h5t_copy(hid_t original) {
|
||||
auto copy = H5Tcopy(original);
|
||||
if (copy == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("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<DataTypeException>("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<DataTypeException>("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<DataTypeException>("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<DataTypeException>("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<DataTypeException>("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<DataTypeException>("Error setting strpad of datatype.");
|
||||
}
|
||||
}
|
||||
|
||||
inline int h5t_get_nmembers(hid_t hid) {
|
||||
auto result = H5Tget_nmembers(hid);
|
||||
|
||||
if (result < 0) {
|
||||
throw DataTypeException("Could not get members of compound datatype");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline char* h5t_get_member_name(hid_t type_id, unsigned membno) {
|
||||
char* name = H5Tget_member_name(type_id, membno);
|
||||
if (name == nullptr) {
|
||||
throw DataTypeException("Failed to get member names of compound datatype");
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
|
||||
inline size_t h5t_get_member_offset(hid_t type_id, unsigned membno) {
|
||||
// Note, this function is peculiar. On failure it returns 0, yet 0 is also
|
||||
// what's returned on failure.
|
||||
return H5Tget_member_offset(type_id, membno);
|
||||
}
|
||||
|
||||
inline hid_t h5t_get_member_type(hid_t type_id, unsigned membno) {
|
||||
hid_t member_id = H5Tget_member_type(type_id, membno);
|
||||
|
||||
if (member_id < 0) {
|
||||
throw DataTypeException("Failed to get member type of compound datatype");
|
||||
}
|
||||
|
||||
return member_id;
|
||||
}
|
||||
|
||||
#if H5_VERSION_GE(1, 12, 0)
|
||||
inline herr_t h5t_reclaim(hid_t type_id, hid_t space_id, hid_t plist_id, void* buf) {
|
||||
herr_t err = H5Treclaim(type_id, space_id, plist_id, buf);
|
||||
if (err < 0) {
|
||||
throw DataTypeException("Failed to reclaim HDF5 internal memory");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline H5T_class_t h5t_get_class(hid_t type_id) {
|
||||
H5T_class_t class_id = H5Tget_class(type_id);
|
||||
if (class_id == H5T_NO_CLASS) {
|
||||
throw DataTypeException("Failed to get class of type");
|
||||
}
|
||||
|
||||
return class_id;
|
||||
}
|
||||
|
||||
inline htri_t h5t_equal(hid_t type1_id, hid_t type2_id) {
|
||||
htri_t equal = H5Tequal(type1_id, type2_id);
|
||||
if (equal < 0) {
|
||||
throw DataTypeException("Failed to compare two datatypes");
|
||||
}
|
||||
|
||||
return equal;
|
||||
}
|
||||
|
||||
inline htri_t h5t_is_variable_str(hid_t type_id) {
|
||||
htri_t is_variable = H5Tis_variable_str(type_id);
|
||||
if (is_variable < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
"Failed to check if string is variable length");
|
||||
}
|
||||
return is_variable;
|
||||
}
|
||||
|
||||
inline herr_t h5t_set_fields(hid_t type_id,
|
||||
size_t spos,
|
||||
size_t epos,
|
||||
size_t esize,
|
||||
size_t mpos,
|
||||
size_t msize) {
|
||||
herr_t err = H5Tset_fields(type_id, spos, epos, esize, mpos, msize);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
"Failed to create custom floating point data type");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5t_set_ebias(hid_t type_id, size_t ebias) {
|
||||
herr_t err = H5Tset_ebias(type_id, ebias);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
"Failed to exponent bias of floating point data type");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hid_t h5t_create(H5T_class_t type, size_t size) {
|
||||
hid_t type_id = H5Tcreate(type, size);
|
||||
if (type_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("Failed to datatype");
|
||||
}
|
||||
|
||||
return type_id;
|
||||
}
|
||||
|
||||
inline herr_t h5t_insert(hid_t parent_id, const char* name, size_t offset, hid_t member_id) {
|
||||
herr_t err = H5Tinsert(parent_id, name, offset, member_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("Failed to not add new member to datatype");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5t_commit2(hid_t loc_id,
|
||||
const char* name,
|
||||
hid_t type_id,
|
||||
hid_t lcpl_id,
|
||||
hid_t tcpl_id,
|
||||
hid_t tapl_id) {
|
||||
herr_t err = H5Tcommit2(loc_id, name, type_id, lcpl_id, tcpl_id, tapl_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("Failed to commit datatype");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline herr_t h5t_close(hid_t type_id) {
|
||||
auto err = H5Tclose(type_id);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("Failed to close datatype");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hid_t h5t_enum_create(hid_t base_id) {
|
||||
hid_t type_id = H5Tenum_create(base_id);
|
||||
if (type_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>("Failed to create new enum datatype");
|
||||
}
|
||||
return type_id;
|
||||
}
|
||||
|
||||
inline herr_t h5t_enum_insert(hid_t type, const char* name, const void* value) {
|
||||
herr_t err = H5Tenum_insert(type, name, value);
|
||||
if (err < 0) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
"Failed to add new member to this enum datatype");
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
inline hid_t h5t_open2(hid_t loc_id, const char* name, hid_t tapl_id) {
|
||||
hid_t datatype_id = H5Topen2(loc_id, name, tapl_id);
|
||||
if (datatype_id == H5I_INVALID_HID) {
|
||||
HDF5ErrMapper::ToException<DataTypeException>(
|
||||
std::string("Unable to open the datatype \"") + name + "\":");
|
||||
}
|
||||
|
||||
return datatype_id;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
98
include/highfive/bits/inspector_stl_span_misc.hpp
Normal file
98
include/highfive/bits/inspector_stl_span_misc.hpp
Normal file
@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include "H5Inspector_decl.hpp"
|
||||
#include "../H5Exception.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <type_traits>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
|
||||
// Anything with the same API as `std::span` can implemented by inheriting from
|
||||
// this class.
|
||||
template <class Span>
|
||||
struct inspector_stl_span {
|
||||
using type = Span;
|
||||
using value_type = unqualified_t<typename Span::value_type>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 1;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
if (!val.empty()) {
|
||||
return ndim + inspector<value_type>::getRank(val[0]);
|
||||
} else {
|
||||
return min_ndim;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
auto rank = getRank(val);
|
||||
std::vector<size_t> sizes(rank, 1ul);
|
||||
sizes[0] = val.size();
|
||||
if (!val.empty()) {
|
||||
auto s = inspector<value_type>::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 void prepare(type& val, const std::vector<size_t>& expected_dims) {
|
||||
auto actual_dims = getDimensions(val);
|
||||
if (actual_dims.size() != expected_dims.size()) {
|
||||
throw DataSpaceException("Mismatching rank.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < actual_dims.size(); ++i) {
|
||||
if (actual_dims[i] != expected_dims[i]) {
|
||||
throw DataSpaceException("Mismatching dimensions.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
||||
if (!val.empty()) {
|
||||
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (const auto& e: val) {
|
||||
inspector<value_type>::serialize(e, subdims, m);
|
||||
m += subsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
|
||||
std::vector<size_t> subdims(dims.begin() + ndim, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (size_t i = 0; i < dims[0]; ++i) {
|
||||
inspector<value_type>::unserialize(vec_align + i * subsize, subdims, val[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
54
include/highfive/bits/squeeze.hpp
Normal file
54
include/highfive/bits/squeeze.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c), 2024, BlueBrain 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)
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "../H5Exception.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
namespace detail {
|
||||
|
||||
/// \brief Squeeze `axes` from `dims`.
|
||||
///
|
||||
/// An axis can only be squeezed if it's dimension is `1`. The elements of
|
||||
/// `axes` must be in the range `0, ..., dims.size()` (exclusive) and don't
|
||||
/// have to be sorted.
|
||||
///
|
||||
/// Example:
|
||||
/// squeeze({1, 3, 2, 1}, {0, 3}) == {3, 2}
|
||||
inline std::vector<size_t> squeeze(const std::vector<size_t>& dims,
|
||||
const std::vector<size_t>& axes) {
|
||||
auto n_dims = dims.size();
|
||||
auto mask = std::vector<bool>(n_dims, false);
|
||||
for (size_t i = 0; i < axes.size(); ++i) {
|
||||
if (axes[i] >= n_dims) {
|
||||
throw Exception("Out of range: axes[" + std::to_string(i) +
|
||||
"] == " + std::to_string(axes[i]) + " >= " + std::to_string(n_dims));
|
||||
}
|
||||
|
||||
mask[axes[i]] = true;
|
||||
}
|
||||
|
||||
auto squeezed_dims = std::vector<size_t>{};
|
||||
for (size_t i = 0; i < n_dims; ++i) {
|
||||
if (!mask[i]) {
|
||||
squeezed_dims.push_back(dims[i]);
|
||||
} else {
|
||||
if (dims[i] != 1) {
|
||||
throw Exception("Squeezing non-unity axis: axes[" + std::to_string(i) +
|
||||
"] = " + std::to_string(axes[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return squeezed_dims;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace HighFive
|
||||
14
include/highfive/bits/string_padding.hpp
Normal file
14
include/highfive/bits/string_padding.hpp
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <H5Tpublic.h>
|
||||
|
||||
namespace HighFive {
|
||||
|
||||
enum class StringPadding : std::underlying_type<H5T_str_t>::type {
|
||||
NullTerminated = H5T_STR_NULLTERM,
|
||||
NullPadded = H5T_STR_NULLPAD,
|
||||
SpacePadded = H5T_STR_SPACEPAD
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
22
include/highfive/bits/xtensor_header_version.hpp
Normal file
22
include/highfive/bits/xtensor_header_version.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
// clang-format off
|
||||
#if HIGHFIVE_XTENSOR_HEADER_VERSION == 0
|
||||
#if __cplusplus >= 201703L
|
||||
#if __has_include(<xtensor/xtensor.hpp>)
|
||||
#define HIGHFIVE_XTENSOR_HEADER_VERSION 1
|
||||
#elif __has_include(<xtensor/containers/xtensor.hpp>)
|
||||
#define HIGHFIVE_XTENSOR_HEADER_VERSION 2
|
||||
#else
|
||||
#error "Unable to guess HIGHFIVE_XTENSOR_HEADER_VERSION. Please set manually."
|
||||
#endif
|
||||
#elif __cplusplus == 201402L
|
||||
// XTensor 0.26 and newer require C++17. Hence, if we have C++14, only
|
||||
// `HIGHFIVE_XTENSOR_HEADER_VERSION == 1` makes sense.
|
||||
#define HIGHFIVE_XTENSOR_HEADER_VERSION 1
|
||||
#elif defined(_MSC_VER) && __cplusplus == 199711L
|
||||
#error \
|
||||
"Use /Zc:__cplusplus to make MSVC set __cplusplus correctly or HIGHFIVE_XTENSOR_HEADER_VERSION to skip xtensor version deduction."
|
||||
#else
|
||||
#error "HighFive requires C++14 or newer."
|
||||
#endif
|
||||
#endif
|
||||
// clang-format on
|
||||
4
include/highfive/boost.hpp
Normal file
4
include/highfive/boost.hpp
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include "boost_ublas.hpp"
|
||||
#include "boost_multi_array.hpp"
|
||||
108
include/highfive/boost_multi_array.hpp
Normal file
108
include/highfive/boost_multi_array.hpp
Normal file
@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits/H5Inspector_decl.hpp"
|
||||
#include "H5Exception.hpp"
|
||||
|
||||
#include <boost/multi_array.hpp>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <typename T, size_t Dims>
|
||||
struct inspector<boost::multi_array<T, Dims>> {
|
||||
using type = boost::multi_array<T, Dims>;
|
||||
using value_type = T;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = Dims;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
return ndim + inspector<value_type>::getRank(val.data()[0]);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
auto rank = getRank(val);
|
||||
std::vector<size_t> sizes(rank, 1ul);
|
||||
for (size_t i = 0; i < ndim; ++i) {
|
||||
sizes[i] = val.shape()[i];
|
||||
}
|
||||
if (val.size() != 0) {
|
||||
auto s = inspector<value_type>::getDimensions(val.data()[0]);
|
||||
sizes.resize(ndim + s.size());
|
||||
for (size_t i = 0; i < s.size(); ++i) {
|
||||
sizes[ndim + i] = s[i];
|
||||
}
|
||||
}
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& 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<typename type::index, Dims> ext;
|
||||
std::copy(dims.begin(), dims.begin() + ndim, ext.begin());
|
||||
val.resize(ext);
|
||||
std::vector<size_t> next_dims(dims.begin() + Dims, dims.end());
|
||||
std::size_t size = std::accumulate(dims.begin(),
|
||||
dims.begin() + Dims,
|
||||
std::size_t{1},
|
||||
std::multiplies<size_t>());
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
inspector<value_type>::prepare(*(val.origin() + i), next_dims);
|
||||
}
|
||||
}
|
||||
|
||||
static void assert_c_order(const type& val) {
|
||||
if (!(val.storage_order() == boost::c_storage_order())) {
|
||||
throw DataTypeException("Only C storage order is supported for 'boost::multi_array'.");
|
||||
}
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
assert_c_order(val);
|
||||
return inspector<value_type>::data(*val.data());
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
assert_c_order(val);
|
||||
return inspector<value_type>::data(*val.data());
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
||||
assert_c_order(val);
|
||||
size_t size = val.num_elements();
|
||||
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
inspector<value_type>::serialize(*(val.origin() + i), subdims, m + i * subsize);
|
||||
}
|
||||
}
|
||||
|
||||
template <class It>
|
||||
static void unserialize(It vec_align, const std::vector<size_t>& dims, type& val) {
|
||||
assert_c_order(val);
|
||||
std::vector<size_t> 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<value_type>::unserialize(vec_align + i * subsize,
|
||||
next_dims,
|
||||
*(val.origin() + i));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
24
include/highfive/boost_span.hpp
Normal file
24
include/highfive/boost_span.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits/H5Inspector_decl.hpp"
|
||||
#include "H5Exception.hpp"
|
||||
#include "bits/inspector_stl_span_misc.hpp"
|
||||
|
||||
#include <boost/core/span.hpp>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
template <class T, std::size_t Extent>
|
||||
struct inspector<boost::span<T, Extent>>: public inspector_stl_span<boost::span<T, Extent>> {
|
||||
private:
|
||||
using super = inspector_stl_span<boost::span<T, Extent>>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
79
include/highfive/boost_ublas.hpp
Normal file
79
include/highfive/boost_ublas.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits/H5Inspector_decl.hpp"
|
||||
#include "H5Exception.hpp"
|
||||
|
||||
#include <boost/numeric/ublas/matrix.hpp>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <typename T>
|
||||
struct inspector<boost::numeric::ublas::matrix<T>> {
|
||||
using type = boost::numeric::ublas::matrix<T>;
|
||||
using value_type = unqualified_t<T>;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = 2;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_copyable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
return ndim + inspector<value_type>::getRank(val(0, 0));
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
std::vector<size_t> sizes{val.size1(), val.size2()};
|
||||
auto s = inspector<value_type>::getDimensions(val(0, 0));
|
||||
sizes.insert(sizes.end(), s.begin(), s.end());
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& 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<value_type>::data(val(0, 0));
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
return inspector<value_type>::data(val(0, 0));
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
||||
size_t size = val.size1() * val.size2();
|
||||
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
|
||||
size_t subsize = compute_total_size(subdims);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
inspector<value_type>::serialize(*(&val(0, 0) + i), subdims, m + i * subsize);
|
||||
}
|
||||
}
|
||||
|
||||
static void unserialize(const hdf5_type* vec_align,
|
||||
const std::vector<size_t>& dims,
|
||||
type& val) {
|
||||
std::vector<size_t> 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<value_type>::unserialize(vec_align + i * subsize,
|
||||
next_dims,
|
||||
*(&val(0, 0) + i));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
161
include/highfive/eigen.hpp
Normal file
161
include/highfive/eigen.hpp
Normal file
@ -0,0 +1,161 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits/H5Inspector_decl.hpp"
|
||||
#include "H5Exception.hpp"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/Dense>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <class EigenType>
|
||||
struct eigen_inspector {
|
||||
using type = EigenType;
|
||||
using value_type = typename EigenType::Scalar;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = base_type;
|
||||
|
||||
|
||||
static_assert(int(EigenType::ColsAtCompileTime) == int(EigenType::MaxColsAtCompileTime),
|
||||
"Padding isn't supported.");
|
||||
static_assert(int(EigenType::RowsAtCompileTime) == int(EigenType::MaxRowsAtCompileTime),
|
||||
"Padding isn't supported.");
|
||||
|
||||
static constexpr bool is_row_major() {
|
||||
return EigenType::ColsAtCompileTime == 1 || EigenType::RowsAtCompileTime == 1 ||
|
||||
EigenType::IsRowMajor;
|
||||
}
|
||||
|
||||
|
||||
static constexpr size_t ndim = 2;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
static constexpr bool is_trivially_copyable = is_row_major() &&
|
||||
std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
return ndim + inspector<value_type>::getRank(val.data()[0]);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
std::vector<size_t> sizes{static_cast<size_t>(val.rows()), static_cast<size_t>(val.cols())};
|
||||
auto s = inspector<value_type>::getDimensions(val.data()[0]);
|
||||
sizes.insert(sizes.end(), s.begin(), s.end());
|
||||
return sizes;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
if (dims[0] != static_cast<size_t>(val.rows()) ||
|
||||
dims[1] != static_cast<size_t>(val.cols())) {
|
||||
val.resize(static_cast<typename type::Index>(dims[0]),
|
||||
static_cast<typename type::Index>(dims[1]));
|
||||
}
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(*val.data());
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(*val.data());
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
||||
Eigen::Index n_rows = val.rows();
|
||||
Eigen::Index n_cols = val.cols();
|
||||
|
||||
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
|
||||
auto subsize = compute_total_size(subdims);
|
||||
for (Eigen::Index i = 0; i < n_rows; ++i) {
|
||||
for (Eigen::Index j = 0; j < n_cols; ++j) {
|
||||
inspector<value_type>::serialize(val(i, j), dims, m);
|
||||
m += subsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unserialize(const hdf5_type* vec_align,
|
||||
const std::vector<size_t>& 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());
|
||||
}
|
||||
|
||||
auto n_rows = static_cast<Eigen::Index>(dims[0]);
|
||||
auto n_cols = static_cast<Eigen::Index>(dims[1]);
|
||||
|
||||
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
|
||||
auto subsize = compute_total_size(subdims);
|
||||
for (Eigen::Index i = 0; i < n_rows; ++i) {
|
||||
for (Eigen::Index j = 0; j < n_cols; ++j) {
|
||||
inspector<value_type>::unserialize(vec_align, subdims, val(i, j));
|
||||
vec_align += subsize;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, int M, int N, int Options>
|
||||
struct inspector<Eigen::Matrix<T, M, N, Options>>
|
||||
: public eigen_inspector<Eigen::Matrix<T, M, N, Options>> {
|
||||
private:
|
||||
using super = eigen_inspector<Eigen::Matrix<T, M, N, Options>>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
template <typename T, int M, int N, int Options>
|
||||
struct inspector<Eigen::Array<T, M, N, Options>>
|
||||
: public eigen_inspector<Eigen::Array<T, M, N, Options>> {
|
||||
private:
|
||||
using super = eigen_inspector<Eigen::Array<T, M, N, Options>>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
|
||||
template <typename PlainObjectType, int MapOptions>
|
||||
struct inspector<Eigen::Map<PlainObjectType, MapOptions>>
|
||||
: public eigen_inspector<Eigen::Map<PlainObjectType, MapOptions>> {
|
||||
private:
|
||||
using super = eigen_inspector<Eigen::Map<PlainObjectType, MapOptions>>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
if (dims[0] != static_cast<size_t>(val.rows()) ||
|
||||
dims[1] != static_cast<size_t>(val.cols())) {
|
||||
throw DataSetException("Eigen::Map has invalid shape and can't be resized.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
149
include/highfive/experimental/opencv.hpp
Normal file
149
include/highfive/experimental/opencv.hpp
Normal file
@ -0,0 +1,149 @@
|
||||
#pragma once
|
||||
|
||||
#include "../bits/H5Inspector_decl.hpp"
|
||||
#include "../H5Exception.hpp"
|
||||
|
||||
#include <opencv2/opencv.hpp>
|
||||
|
||||
#include "../bits/convert_size_vector.hpp"
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
|
||||
template <class T>
|
||||
struct inspector<cv::Mat_<T>> {
|
||||
using type = cv::Mat_<T>;
|
||||
using value_type = T;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = base_type;
|
||||
|
||||
static void assert_row_major(const type& type) {
|
||||
// Documentation claims that Mat_ is always row-major. However, it
|
||||
// could be padded. The steps/strides are in bytes.
|
||||
int rank = type.dims;
|
||||
size_t ld = sizeof(T);
|
||||
for (int i = rank - 1; i >= 0; --i) {
|
||||
if (static_cast<size_t>(type.step[i]) != ld) {
|
||||
throw DataSetException("Padded cv::Mat_ are not supported.");
|
||||
}
|
||||
|
||||
ld *= static_cast<size_t>(type.size[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static constexpr size_t min_ndim = 2 + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = 1024 + inspector<value_type>::max_ndim;
|
||||
|
||||
// HighFive doesn't support padded OpenCV arrays. Therefore, pretend
|
||||
// that they themselves are trivially copyable. And error out if the
|
||||
// assumption is violated.
|
||||
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_nestable;
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
if (val.empty()) {
|
||||
return min_ndim;
|
||||
|
||||
} else {
|
||||
return static_cast<size_t>(val.dims) +
|
||||
inspector<value_type>::getRank(getAnyElement(val));
|
||||
}
|
||||
}
|
||||
|
||||
static const T& getAnyElement(const type& val) {
|
||||
return *reinterpret_cast<T const*>(val.data);
|
||||
}
|
||||
|
||||
static T& getAnyElement(type& val) {
|
||||
return *reinterpret_cast<T*>(val.data);
|
||||
}
|
||||
|
||||
static size_t getLocalRank(const type& val) {
|
||||
return static_cast<size_t>(val.dims);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
auto local_rank = getLocalRank(val);
|
||||
auto rank = getRank(val);
|
||||
std::vector<size_t> dims(rank, 1ul);
|
||||
|
||||
if (val.empty()) {
|
||||
dims[0] = 0ul;
|
||||
dims[1] = 1ul;
|
||||
return dims;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < local_rank; ++i) {
|
||||
dims[i] = static_cast<size_t>(val.size[static_cast<int>(i)]);
|
||||
}
|
||||
|
||||
auto s = inspector<value_type>::getDimensions(getAnyElement(val));
|
||||
std::copy(s.cbegin(), s.cend(), dims.begin() + static_cast<int>(local_rank));
|
||||
return dims;
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
auto subdims = detail::convertSizeVector<int>(dims);
|
||||
val.create(static_cast<int>(subdims.size()), subdims.data());
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
assert_row_major(val);
|
||||
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
|
||||
}
|
||||
|
||||
if (val.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(getAnyElement(val));
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
assert_row_major(val);
|
||||
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
|
||||
}
|
||||
|
||||
if (val.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(getAnyElement(val));
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
||||
if (val.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto local_rank = val.dims;
|
||||
auto subdims = std::vector<size_t>(dims.begin() + local_rank, dims.end());
|
||||
auto subsize = compute_total_size(subdims);
|
||||
for (auto it = val.begin(); it != val.end(); ++it) {
|
||||
inspector<value_type>::serialize(*it, subdims, m);
|
||||
m += subsize;
|
||||
}
|
||||
}
|
||||
|
||||
static void unserialize(const hdf5_type* vec_align,
|
||||
const std::vector<size_t>& dims,
|
||||
type& val) {
|
||||
auto local_rank = val.dims;
|
||||
auto subdims = std::vector<size_t>(dims.begin() + local_rank, dims.end());
|
||||
auto subsize = compute_total_size(subdims);
|
||||
for (auto it = val.begin(); it != val.end(); ++it) {
|
||||
inspector<value_type>::unserialize(vec_align, subdims, *it);
|
||||
vec_align += subsize;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
117
include/highfive/h5easy_bits/H5Easy_Eigen.hpp
Normal file
117
include/highfive/h5easy_bits/H5Easy_Eigen.hpp
Normal file
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "../H5Easy.hpp"
|
||||
#include "H5Easy_misc.hpp"
|
||||
#include "H5Easy_scalar.hpp"
|
||||
|
||||
#ifdef H5_USE_EIGEN
|
||||
|
||||
#include "../eigen.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct io_impl<T, typename std::enable_if<std::is_base_of<Eigen::DenseBase<T>, T>::value>::type> {
|
||||
using EigenIndex = Eigen::DenseIndex;
|
||||
|
||||
// When creating a dataset for an Eigen object, the shape of the dataset is
|
||||
// 1D for vectors. (legacy reasons)
|
||||
inline static std::vector<size_t> file_shape(const T& data) {
|
||||
if (std::decay<T>::type::RowsAtCompileTime == 1) {
|
||||
return {static_cast<size_t>(data.cols())};
|
||||
}
|
||||
if (std::decay<T>::type::ColsAtCompileTime == 1) {
|
||||
return {static_cast<size_t>(data.rows())};
|
||||
}
|
||||
return inspector<T>::getDimensions(data);
|
||||
}
|
||||
|
||||
// The shape of an Eigen object as used in HighFive core.
|
||||
inline static std::vector<size_t> mem_shape(const T& data) {
|
||||
return inspector<T>::getDimensions(data);
|
||||
}
|
||||
|
||||
// The shape of an Eigen object as used in HighFive core.
|
||||
template <class D>
|
||||
inline static std::vector<size_t> mem_shape(const File& file,
|
||||
const std::string& path,
|
||||
const D& dataset) {
|
||||
std::vector<size_t> dims = dataset.getDimensions();
|
||||
|
||||
if (dims.size() == 1 && T::RowsAtCompileTime == 1) {
|
||||
return std::vector<size_t>{1, dims[0]};
|
||||
}
|
||||
if (dims.size() == 1 && T::ColsAtCompileTime == 1) {
|
||||
return std::vector<size_t>{dims[0], 1};
|
||||
}
|
||||
if (dims.size() == 2) {
|
||||
return dims;
|
||||
}
|
||||
|
||||
throw detail::error(file, path, "H5Easy::load: Inconsistent rank");
|
||||
}
|
||||
|
||||
inline static DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
using value_type = typename std::decay<T>::type::Scalar;
|
||||
|
||||
std::vector<size_t> file_dims = file_shape(data);
|
||||
std::vector<size_t> mem_dims = mem_shape(data);
|
||||
DataSet dataset = initDataset<value_type>(file, path, file_dims, options);
|
||||
dataset.reshapeMemSpace(mem_dims).write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
inline static T load(const File& file, const std::string& path) {
|
||||
DataSet dataset = file.getDataSet(path);
|
||||
std::vector<size_t> dims = mem_shape(file, path, dataset);
|
||||
return dataset.reshapeMemSpace(dims).template read<T>();
|
||||
}
|
||||
|
||||
inline static Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
using value_type = typename std::decay<T>::type::Scalar;
|
||||
|
||||
std::vector<size_t> file_dims = file_shape(data);
|
||||
std::vector<size_t> mem_dims = mem_shape(data);
|
||||
Attribute attribute = initAttribute<value_type>(file, path, key, file_dims, options);
|
||||
attribute.reshapeMemSpace(mem_dims).write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
inline static T loadAttribute(const File& file,
|
||||
const std::string& path,
|
||||
const std::string& key) {
|
||||
DataSet dataset = file.getDataSet(path);
|
||||
Attribute attribute = dataset.getAttribute(key);
|
||||
DataSpace dataspace = attribute.getSpace();
|
||||
std::vector<size_t> dims = mem_shape(file, path, dataspace);
|
||||
return attribute.reshapeMemSpace(dims).template read<T>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace H5Easy
|
||||
|
||||
#endif // H5_USE_EIGEN
|
||||
179
include/highfive/h5easy_bits/H5Easy_misc.hpp
Normal file
179
include/highfive/h5easy_bits/H5Easy_misc.hpp
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "../H5Easy.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Generate error-stream and return "Exception" (not yet thrown).
|
||||
inline Exception error(const File& file, const std::string& path, const std::string& message) {
|
||||
std::ostringstream ss;
|
||||
ss << message << std::endl
|
||||
<< "Path: " << path << std::endl
|
||||
<< "Filename: " << file.getName() << std::endl;
|
||||
return Exception(ss.str());
|
||||
}
|
||||
|
||||
// Generate specific dump error
|
||||
inline Exception dump_error(File& file, const std::string& path) {
|
||||
if (file.getObjectType(path) == ObjectType::Dataset) {
|
||||
return error(file,
|
||||
path,
|
||||
"H5Easy: Dataset already exists, dump with H5Easy::DumpMode::Overwrite "
|
||||
"to overwrite (with an array of the same shape).");
|
||||
} else {
|
||||
return error(
|
||||
file,
|
||||
path,
|
||||
"H5Easy: path exists, but does not correspond to a Dataset. Dump not possible.");
|
||||
}
|
||||
}
|
||||
|
||||
// get a opened DataSet: nd-array
|
||||
template <class T>
|
||||
inline DataSet initDataset(File& file,
|
||||
const std::string& path,
|
||||
const std::vector<size_t>& shape,
|
||||
const DumpOptions& options) {
|
||||
if (!file.exist(path)) {
|
||||
if (!options.compress() && !options.isChunked()) {
|
||||
return file.createDataSet<T>(path, DataSpace(shape), {}, {}, true);
|
||||
} else {
|
||||
std::vector<hsize_t> chunks(shape.begin(), shape.end());
|
||||
if (options.isChunked()) {
|
||||
chunks = options.getChunkSize();
|
||||
if (chunks.size() != shape.size()) {
|
||||
throw error(file, path, "H5Easy::dump: Incorrect rank ChunkSize");
|
||||
}
|
||||
}
|
||||
DataSetCreateProps props;
|
||||
props.add(Chunking(chunks));
|
||||
if (options.compress()) {
|
||||
props.add(Shuffle());
|
||||
props.add(Deflate(options.getCompressionLevel()));
|
||||
}
|
||||
return file.createDataSet<T>(path, DataSpace(shape), props, {}, true);
|
||||
}
|
||||
} else if (options.overwrite() && file.getObjectType(path) == ObjectType::Dataset) {
|
||||
DataSet dataset = file.getDataSet(path);
|
||||
if (dataset.getDimensions() != shape) {
|
||||
throw error(file, path, "H5Easy::dump: Inconsistent dimensions");
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
throw dump_error(file, path);
|
||||
}
|
||||
|
||||
// get a opened DataSet: scalar
|
||||
template <class T>
|
||||
inline DataSet initScalarDataset(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
if (!file.exist(path)) {
|
||||
return file.createDataSet<T>(path, DataSpace::From(data), {}, {}, true);
|
||||
} else if (options.overwrite() && file.getObjectType(path) == ObjectType::Dataset) {
|
||||
DataSet dataset = file.getDataSet(path);
|
||||
if (dataset.getElementCount() != 1) {
|
||||
throw error(file, path, "H5Easy::dump: Existing field not a scalar");
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
throw dump_error(file, path);
|
||||
}
|
||||
|
||||
template <class File, class F>
|
||||
auto apply_attr_func_impl(File& file, const std::string& path, F f) {
|
||||
auto type = file.getObjectType(path);
|
||||
if (type == ObjectType::Group) {
|
||||
auto group = file.getGroup(path);
|
||||
return f(group);
|
||||
} else if (type == ObjectType::Dataset) {
|
||||
auto dataset = file.getDataSet(path);
|
||||
return f(dataset);
|
||||
} else {
|
||||
throw error(file, path, "path is not the root, a group or a dataset.");
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto apply_attr_func(const H5Easy::File& file, const std::string& path, F f) {
|
||||
return apply_attr_func_impl(file, path, f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto apply_attr_func(H5Easy::File& file, const std::string& path, F f) {
|
||||
return apply_attr_func_impl(file, path, f);
|
||||
}
|
||||
|
||||
// get a opened Attribute: nd-array
|
||||
template <class T>
|
||||
inline Attribute initAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const std::vector<size_t>& shape,
|
||||
const DumpOptions& options) {
|
||||
auto get_attribute = [&](auto& obj) {
|
||||
if (!obj.hasAttribute(key)) {
|
||||
return obj.template createAttribute<T>(key, DataSpace(shape));
|
||||
} else if (options.overwrite()) {
|
||||
Attribute attribute = obj.getAttribute(key);
|
||||
DataSpace dataspace = attribute.getSpace();
|
||||
if (dataspace.getDimensions() != shape) {
|
||||
throw error(file, path, "H5Easy::dumpAttribute: Inconsistent dimensions");
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
throw error(file,
|
||||
path,
|
||||
"H5Easy: Attribute exists, overwrite with H5Easy::DumpMode::Overwrite.");
|
||||
};
|
||||
|
||||
if (!file.exist(path)) {
|
||||
throw error(file, path, "H5Easy::dumpAttribute: path does not exist");
|
||||
}
|
||||
|
||||
return apply_attr_func(file, path, get_attribute);
|
||||
}
|
||||
|
||||
// get a opened Attribute: scalar
|
||||
template <class T>
|
||||
inline Attribute initScalarAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
auto get_attribute = [&](auto& obj) {
|
||||
if (!obj.hasAttribute(key)) {
|
||||
return obj.template createAttribute<T>(key, DataSpace::From(data));
|
||||
} else if (options.overwrite()) {
|
||||
Attribute attribute = obj.getAttribute(key);
|
||||
DataSpace dataspace = attribute.getSpace();
|
||||
if (dataspace.getElementCount() != 1) {
|
||||
throw error(file, path, "H5Easy::dumpAttribute: Existing field not a scalar");
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
throw error(file,
|
||||
path,
|
||||
"H5Easy: Attribute exists, overwrite with H5Easy::DumpMode::Overwrite.");
|
||||
};
|
||||
|
||||
if (!file.exist(path)) {
|
||||
throw error(file, path, "H5Easy::dumpAttribute: path does not exist");
|
||||
}
|
||||
|
||||
apply_attr_func(file, path, get_attribute);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace H5Easy
|
||||
170
include/highfive/h5easy_bits/H5Easy_public.hpp
Normal file
170
include/highfive/h5easy_bits/H5Easy_public.hpp
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "../H5Easy.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
|
||||
inline Compression::Compression(bool enable) {
|
||||
if (enable) {
|
||||
m_compression_level = 9;
|
||||
} else {
|
||||
m_compression_level = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline Compression::Compression(T level)
|
||||
: m_compression_level(static_cast<unsigned>(level)) {}
|
||||
|
||||
inline unsigned Compression::get() const {
|
||||
return m_compression_level;
|
||||
}
|
||||
|
||||
inline void DumpOptions::set(DumpMode mode) {
|
||||
m_overwrite = static_cast<bool>(mode);
|
||||
}
|
||||
|
||||
inline void DumpOptions::set(Flush mode) {
|
||||
m_flush = static_cast<bool>(mode);
|
||||
}
|
||||
|
||||
inline void DumpOptions::set(const Compression& level) {
|
||||
m_compression_level = level.get();
|
||||
}
|
||||
|
||||
template <class T, class... Args>
|
||||
inline void DumpOptions::set(T arg, Args... args) {
|
||||
set(arg);
|
||||
set(args...);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void DumpOptions::setChunkSize(const std::vector<T>& shape) {
|
||||
m_chunk_size = std::vector<hsize_t>(shape.begin(), shape.end());
|
||||
}
|
||||
|
||||
inline void DumpOptions::setChunkSize(std::initializer_list<size_t> shape) {
|
||||
m_chunk_size = std::vector<hsize_t>(shape.begin(), shape.end());
|
||||
}
|
||||
|
||||
inline bool DumpOptions::overwrite() const {
|
||||
return m_overwrite;
|
||||
}
|
||||
|
||||
inline bool DumpOptions::flush() const {
|
||||
return m_flush;
|
||||
}
|
||||
|
||||
inline bool DumpOptions::compress() const {
|
||||
return m_compression_level > 0;
|
||||
}
|
||||
|
||||
inline unsigned DumpOptions::getCompressionLevel() const {
|
||||
return m_compression_level;
|
||||
}
|
||||
|
||||
inline bool DumpOptions::isChunked() const {
|
||||
return m_chunk_size.size() > 0;
|
||||
}
|
||||
|
||||
inline std::vector<hsize_t> DumpOptions::getChunkSize() const {
|
||||
return m_chunk_size;
|
||||
}
|
||||
|
||||
inline size_t getSize(const File& file, const std::string& path) {
|
||||
return file.getDataSet(path).getElementCount();
|
||||
}
|
||||
|
||||
inline std::vector<size_t> getShape(const File& file, const std::string& path) {
|
||||
return file.getDataSet(path).getDimensions();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
return detail::io_impl<T>::dump(file, path, data, options);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file, const std::string& path, const T& data, DumpMode mode) {
|
||||
return detail::io_impl<T>::dump(file, path, data, DumpOptions(mode));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::vector<size_t>& idx,
|
||||
const DumpOptions& options) {
|
||||
return detail::io_impl<T>::dump_extend(file, path, data, idx, options);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::initializer_list<size_t>& idx,
|
||||
const DumpOptions& options) {
|
||||
return detail::io_impl<T>::dump_extend(file, path, data, idx, options);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::vector<size_t>& idx) {
|
||||
return detail::io_impl<T>::dump_extend(file, path, data, idx, DumpOptions());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::initializer_list<size_t>& idx) {
|
||||
return detail::io_impl<T>::dump_extend(file, path, data, idx, DumpOptions());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T load(const File& file, const std::string& path, const std::vector<size_t>& idx) {
|
||||
return detail::io_impl<T>::load_part(file, path, idx);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T load(const File& file, const std::string& path) {
|
||||
return detail::io_impl<T>::load(file, path);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
DumpMode mode) {
|
||||
return detail::io_impl<T>::dumpAttribute(file, path, key, data, DumpOptions(mode));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
return detail::io_impl<T>::dumpAttribute(file, path, key, data, options);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline T loadAttribute(const File& file, const std::string& path, const std::string& key) {
|
||||
return detail::io_impl<T>::loadAttribute(file, path, key);
|
||||
}
|
||||
|
||||
} // namespace H5Easy
|
||||
88
include/highfive/h5easy_bits/H5Easy_scalar.hpp
Normal file
88
include/highfive/h5easy_bits/H5Easy_scalar.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "../H5Easy.hpp"
|
||||
#include "H5Easy_misc.hpp"
|
||||
#include "default_io_impl.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
|
||||
namespace detail {
|
||||
|
||||
/*
|
||||
Base template for partial specialization: the fallback if specialized templates don't match.
|
||||
Used e.g. for scalars.
|
||||
*/
|
||||
template <typename T, typename = void>
|
||||
struct io_impl: public default_io_impl<T> {
|
||||
inline static DataSet dump_extend(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const std::vector<size_t>& idx,
|
||||
const DumpOptions& options) {
|
||||
std::vector<size_t> ones(idx.size(), 1);
|
||||
|
||||
if (file.exist(path)) {
|
||||
DataSet dataset = file.getDataSet(path);
|
||||
std::vector<size_t> dims = dataset.getDimensions();
|
||||
std::vector<size_t> shape = dims;
|
||||
if (dims.size() != idx.size()) {
|
||||
throw detail::error(
|
||||
file,
|
||||
path,
|
||||
"H5Easy::dump: Dimension of the index and the existing field do not match");
|
||||
}
|
||||
for (size_t i = 0; i < dims.size(); ++i) {
|
||||
shape[i] = std::max(dims[i], idx[i] + 1);
|
||||
}
|
||||
if (shape != dims) {
|
||||
dataset.resize(shape);
|
||||
}
|
||||
dataset.select(idx, ones).write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
const size_t unlim = DataSpace::UNLIMITED;
|
||||
std::vector<size_t> unlim_shape(idx.size(), unlim);
|
||||
std::vector<hsize_t> chunks(idx.size(), 10);
|
||||
if (options.isChunked()) {
|
||||
chunks = options.getChunkSize();
|
||||
if (chunks.size() != idx.size()) {
|
||||
throw error(file, path, "H5Easy::dump: Incorrect dimension ChunkSize");
|
||||
}
|
||||
}
|
||||
std::vector<size_t> shape(idx.size());
|
||||
for (size_t i = 0; i < idx.size(); ++i) {
|
||||
shape[i] = idx[i] + 1;
|
||||
}
|
||||
DataSpace dataspace = DataSpace(shape, unlim_shape);
|
||||
DataSetCreateProps props;
|
||||
props.add(Chunking(chunks));
|
||||
DataSet dataset = file.createDataSet(path, dataspace, AtomicType<T>(), props, {}, true);
|
||||
dataset.select(idx, ones).write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
inline static T load_part(const File& file,
|
||||
const std::string& path,
|
||||
const std::vector<size_t>& idx) {
|
||||
std::vector<size_t> ones(idx.size(), 1);
|
||||
return file.getDataSet(path).select(idx, ones).read<T>();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace H5Easy
|
||||
69
include/highfive/h5easy_bits/default_io_impl.hpp
Normal file
69
include/highfive/h5easy_bits/default_io_impl.hpp
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
|
||||
*
|
||||
* 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 "../H5Easy.hpp"
|
||||
#include "H5Easy_misc.hpp"
|
||||
#include "H5Easy_scalar.hpp"
|
||||
|
||||
namespace H5Easy {
|
||||
namespace detail {
|
||||
|
||||
using HighFive::details::inspector;
|
||||
|
||||
template <typename T>
|
||||
struct default_io_impl {
|
||||
inline static std::vector<size_t> shape(const T& data) {
|
||||
return inspector<T>::getDimensions(data);
|
||||
}
|
||||
|
||||
inline static DataSet dump(File& file,
|
||||
const std::string& path,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
using value_type = typename inspector<T>::base_type;
|
||||
DataSet dataset = initDataset<value_type>(file, path, shape(data), options);
|
||||
dataset.write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return dataset;
|
||||
}
|
||||
|
||||
inline static T load(const File& file, const std::string& path) {
|
||||
return file.getDataSet(path).read<T>();
|
||||
}
|
||||
|
||||
inline static Attribute dumpAttribute(File& file,
|
||||
const std::string& path,
|
||||
const std::string& key,
|
||||
const T& data,
|
||||
const DumpOptions& options) {
|
||||
using value_type = typename inspector<T>::base_type;
|
||||
Attribute attribute = initAttribute<value_type>(file, path, key, shape(data), options);
|
||||
attribute.write(data);
|
||||
if (options.flush()) {
|
||||
file.flush();
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
|
||||
inline static T loadAttribute(const File& file,
|
||||
const std::string& path,
|
||||
const std::string& key) {
|
||||
auto read_attribute = [&key](const auto& obj) {
|
||||
return obj.getAttribute(key).template read<T>();
|
||||
};
|
||||
|
||||
return apply_attr_func(file, path, read_attribute);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace H5Easy
|
||||
19
include/highfive/half_float.hpp
Normal file
19
include/highfive/half_float.hpp
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <half.hpp>
|
||||
|
||||
namespace HighFive {
|
||||
using float16_t = half_float::half;
|
||||
|
||||
template <>
|
||||
inline AtomicType<float16_t>::AtomicType() {
|
||||
_hid = detail::h5t_copy(H5T_NATIVE_FLOAT);
|
||||
// Sign position, exponent position, exponent size, mantissa position, mantissa size
|
||||
detail::h5t_set_fields(_hid, 15, 10, 5, 0, 10);
|
||||
// Total datatype size (in bytes)
|
||||
detail::h5t_set_size(_hid, 2);
|
||||
// Floating point exponent bias
|
||||
detail::h5t_set_ebias(_hid, 15);
|
||||
}
|
||||
|
||||
} // namespace HighFive
|
||||
13
include/highfive/highfive.hpp
Normal file
13
include/highfive/highfive.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <highfive/H5Attribute.hpp>
|
||||
#include <highfive/H5DataSet.hpp>
|
||||
#include <highfive/H5DataSpace.hpp>
|
||||
#include <highfive/H5DataType.hpp>
|
||||
#include <highfive/H5File.hpp>
|
||||
#include <highfive/H5Group.hpp>
|
||||
#include <highfive/H5PropertyList.hpp>
|
||||
#include <highfive/H5Reference.hpp>
|
||||
#include <highfive/H5Selection.hpp>
|
||||
#include <highfive/H5Utility.hpp>
|
||||
#include <highfive/H5Version.hpp>
|
||||
33
include/highfive/span.hpp
Normal file
33
include/highfive/span.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2024 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 "bits/H5Inspector_decl.hpp"
|
||||
#include "bits/inspector_stl_span_misc.hpp"
|
||||
|
||||
#include <span>
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <class T, std::size_t Extent>
|
||||
struct inspector<std::span<T, Extent>>: public inspector_stl_span<std::span<T, Extent>> {
|
||||
private:
|
||||
using super = inspector_stl_span<std::span<T, Extent>>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
221
include/highfive/xtensor.hpp
Normal file
221
include/highfive/xtensor.hpp
Normal file
@ -0,0 +1,221 @@
|
||||
#pragma once
|
||||
|
||||
#include "bits/H5Inspector_decl.hpp"
|
||||
#include "H5Exception.hpp"
|
||||
#include "bits/xtensor_header_version.hpp"
|
||||
|
||||
#if HIGHFIVE_XTENSOR_HEADER_VERSION == 1
|
||||
#include <xtensor/xtensor.hpp>
|
||||
#include <xtensor/xarray.hpp>
|
||||
#include <xtensor/xadapt.hpp>
|
||||
#elif HIGHFIVE_XTENSOR_HEADER_VERSION == 2
|
||||
#include <xtensor/containers/xtensor.hpp>
|
||||
#include <xtensor/containers/xarray.hpp>
|
||||
#include <xtensor/containers/xadapt.hpp>
|
||||
#else
|
||||
#error "Set HIGHFIVE_XTENSOR_HEADER_VERSION to `1` for pre 0.26; `2` otherwise."
|
||||
#endif
|
||||
|
||||
namespace HighFive {
|
||||
namespace details {
|
||||
|
||||
template <class XTensor>
|
||||
struct xtensor_get_rank;
|
||||
|
||||
template <typename T, size_t N, xt::layout_type L>
|
||||
struct xtensor_get_rank<xt::xtensor<T, N, L>> {
|
||||
static constexpr size_t value = N;
|
||||
};
|
||||
|
||||
template <class EC, size_t N, xt::layout_type L, class Tag>
|
||||
struct xtensor_get_rank<xt::xtensor_adaptor<EC, N, L, Tag>> {
|
||||
static constexpr size_t value = N;
|
||||
};
|
||||
|
||||
template <class Derived, class XTensorType, xt::layout_type L>
|
||||
struct xtensor_inspector_base {
|
||||
using type = XTensorType;
|
||||
using value_type = typename type::value_type;
|
||||
using base_type = typename inspector<value_type>::base_type;
|
||||
using hdf5_type = base_type;
|
||||
|
||||
static_assert(std::is_same<value_type, base_type>::value,
|
||||
"HighFive's XTensor support only works for scalar elements.");
|
||||
|
||||
static constexpr bool IsConstExprRowMajor = L == xt::layout_type::row_major;
|
||||
static constexpr bool is_trivially_copyable = IsConstExprRowMajor &&
|
||||
std::is_trivially_copyable<value_type>::value &&
|
||||
inspector<value_type>::is_trivially_copyable;
|
||||
|
||||
static constexpr bool is_trivially_nestable = false;
|
||||
|
||||
static size_t getRank(const type& val) {
|
||||
// Non-scalar elements are not supported.
|
||||
return val.shape().size();
|
||||
}
|
||||
|
||||
static const value_type& getAnyElement(const type& val) {
|
||||
return val.unchecked(0);
|
||||
}
|
||||
|
||||
static value_type& getAnyElement(type& val) {
|
||||
return val.unchecked(0);
|
||||
}
|
||||
|
||||
static std::vector<size_t> getDimensions(const type& val) {
|
||||
auto shape = val.shape();
|
||||
return {shape.begin(), shape.end()};
|
||||
}
|
||||
|
||||
static void prepare(type& val, const std::vector<size_t>& dims) {
|
||||
val.resize(Derived::shapeFromDims(dims));
|
||||
}
|
||||
|
||||
static hdf5_type* data(type& val) {
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<XTensor>::data`.");
|
||||
}
|
||||
|
||||
if (val.size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(getAnyElement(val));
|
||||
}
|
||||
|
||||
static const hdf5_type* data(const type& val) {
|
||||
if (!is_trivially_copyable) {
|
||||
throw DataSetException("Invalid used of `inspector<XTensor>::data`.");
|
||||
}
|
||||
|
||||
if (val.size() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return inspector<value_type>::data(getAnyElement(val));
|
||||
}
|
||||
|
||||
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
||||
// since we only support scalar types we know all dims belong to us.
|
||||
size_t size = compute_total_size(dims);
|
||||
xt::adapt(m, size, xt::no_ownership(), dims) = val;
|
||||
}
|
||||
|
||||
static void unserialize(const hdf5_type* vec_align,
|
||||
const std::vector<size_t>& dims,
|
||||
type& val) {
|
||||
// since we only support scalar types we know all dims belong to us.
|
||||
size_t size = compute_total_size(dims);
|
||||
val = xt::adapt(vec_align, size, xt::no_ownership(), dims);
|
||||
}
|
||||
};
|
||||
|
||||
template <class XTensorType, xt::layout_type L>
|
||||
struct xtensor_inspector
|
||||
: public xtensor_inspector_base<xtensor_inspector<XTensorType, L>, XTensorType, L> {
|
||||
private:
|
||||
using super = xtensor_inspector_base<xtensor_inspector<XTensorType, L>, XTensorType, L>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
|
||||
static constexpr size_t ndim = xtensor_get_rank<XTensorType>::value;
|
||||
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
||||
|
||||
static std::array<size_t, ndim> shapeFromDims(const std::vector<size_t>& dims) {
|
||||
std::array<size_t, ndim> shape;
|
||||
std::copy(dims.cbegin(), dims.cend(), shape.begin());
|
||||
return shape;
|
||||
}
|
||||
};
|
||||
|
||||
template <class XArrayType, xt::layout_type L>
|
||||
struct xarray_inspector
|
||||
: public xtensor_inspector_base<xarray_inspector<XArrayType, L>, XArrayType, L> {
|
||||
private:
|
||||
using super = xtensor_inspector_base<xarray_inspector<XArrayType, L>, XArrayType, L>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
|
||||
static constexpr size_t min_ndim = 0 + inspector<value_type>::min_ndim;
|
||||
static constexpr size_t max_ndim = 1024 + inspector<value_type>::max_ndim;
|
||||
|
||||
static const std::vector<size_t>& shapeFromDims(const std::vector<size_t>& dims) {
|
||||
return dims;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, size_t N, xt::layout_type L>
|
||||
struct inspector<xt::xtensor<T, N, L>>: public xtensor_inspector<xt::xtensor<T, N, L>, L> {
|
||||
private:
|
||||
using super = xtensor_inspector<xt::xtensor<T, N, L>, L>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
template <typename T, xt::layout_type L>
|
||||
struct inspector<xt::xarray<T, L>>: public xarray_inspector<xt::xarray<T, L>, L> {
|
||||
private:
|
||||
using super = xarray_inspector<xt::xarray<T, L>, L>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
template <typename CT, class... S>
|
||||
struct inspector<xt::xview<CT, S...>>
|
||||
: public xarray_inspector<xt::xview<CT, S...>, xt::layout_type::any> {
|
||||
private:
|
||||
using super = xarray_inspector<xt::xview<CT, S...>, xt::layout_type::any>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
|
||||
template <class EC, xt::layout_type L, class SC, class Tag>
|
||||
struct inspector<xt::xarray_adaptor<EC, L, SC, Tag>>
|
||||
: public xarray_inspector<xt::xarray_adaptor<EC, L, SC, Tag>, xt::layout_type::any> {
|
||||
private:
|
||||
using super = xarray_inspector<xt::xarray_adaptor<EC, L, SC, Tag>, xt::layout_type::any>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
template <class EC, size_t N, xt::layout_type L, class Tag>
|
||||
struct inspector<xt::xtensor_adaptor<EC, N, L, Tag>>
|
||||
: public xtensor_inspector<xt::xtensor_adaptor<EC, N, L, Tag>, xt::layout_type::any> {
|
||||
private:
|
||||
using super = xtensor_inspector<xt::xtensor_adaptor<EC, N, L, Tag>, xt::layout_type::any>;
|
||||
|
||||
public:
|
||||
using type = typename super::type;
|
||||
using value_type = typename super::value_type;
|
||||
using base_type = typename super::base_type;
|
||||
using hdf5_type = typename super::hdf5_type;
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
} // namespace HighFive
|
||||
28
lib/cmake/HighFive/HighFiveConfig.cmake
Normal file
28
lib/cmake/HighFive/HighFiveConfig.cmake
Normal file
@ -0,0 +1,28 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
|
||||
if(NOT DEFINED HIGHFIVE_FIND_HDF5)
|
||||
set(HIGHFIVE_FIND_HDF5 On)
|
||||
endif()
|
||||
|
||||
if(HIGHFIVE_FIND_HDF5)
|
||||
find_dependency(HDF5)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET HighFive)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/HighFiveTargets.cmake")
|
||||
|
||||
if(HDF5_IS_PARALLEL)
|
||||
find_dependency(MPI)
|
||||
target_link_libraries(HighFive::HighFive INTERFACE MPI::MPI_C MPI::MPI_CXX)
|
||||
endif()
|
||||
|
||||
add_library(HighFive ALIAS HighFive::HighFive)
|
||||
add_library(HighFiveInclude ALIAS HighFive::Include)
|
||||
endif()
|
||||
|
||||
if(HIGHFIVE_XTENSOR_HEADER_VERSION)
|
||||
target_compile_definitions(HighFive::HighFive PUBLIC
|
||||
HIGHFIVE_XTENSOR_HEADER_VERSION=${HIGHFIVE_XTENSOR_HEADER_VERSION}
|
||||
)
|
||||
endif()
|
||||
|
||||
48
lib/cmake/HighFive/HighFiveConfigVersion.cmake
Normal file
48
lib/cmake/HighFive/HighFiveConfigVersion.cmake
Normal file
@ -0,0 +1,48 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
set(PACKAGE_VERSION "3.0.0")
|
||||
|
||||
if (PACKAGE_FIND_VERSION_RANGE)
|
||||
# Package version must be in the requested version range
|
||||
if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN)
|
||||
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX)
|
||||
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX)))
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
endif()
|
||||
else()
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed project requested no architecture check, don't perform the check
|
||||
if("FALSE")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
||||
105
lib/cmake/HighFive/HighFiveTargets.cmake
Normal file
105
lib/cmake/HighFive/HighFiveTargets.cmake
Normal file
@ -0,0 +1,105 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
|
||||
message(FATAL_ERROR "CMake >= 2.6.0 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.6...3.21)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_targetsDefined)
|
||||
set(_targetsNotDefined)
|
||||
set(_expectedTargets)
|
||||
foreach(_expectedTarget HighFive::HighFive HighFive::Include)
|
||||
list(APPEND _expectedTargets ${_expectedTarget})
|
||||
if(NOT TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsNotDefined ${_expectedTarget})
|
||||
endif()
|
||||
if(TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsDefined ${_expectedTarget})
|
||||
endif()
|
||||
endforeach()
|
||||
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${_targetsDefined}" STREQUAL "")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
|
||||
endif()
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target HighFive::HighFive
|
||||
add_library(HighFive::HighFive INTERFACE IMPORTED)
|
||||
|
||||
set_target_properties(HighFive::HighFive PROPERTIES
|
||||
INTERFACE_LINK_LIBRARIES "HighFive::Include;HDF5::HDF5"
|
||||
)
|
||||
|
||||
# Create imported target HighFive::Include
|
||||
add_library(HighFive::Include INTERFACE IMPORTED)
|
||||
|
||||
set_target_properties(HighFive::Include PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
|
||||
)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
||||
message(FATAL_ERROR "This file relies on consumers using CMake 3.0.0 or greater.")
|
||||
endif()
|
||||
|
||||
# Load information for each installed configuration.
|
||||
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
file(GLOB CONFIG_FILES "${_DIR}/HighFiveTargets-*.cmake")
|
||||
foreach(f ${CONFIG_FILES})
|
||||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||
if(NOT EXISTS "${file}" )
|
||||
message(FATAL_ERROR "The imported target \"${target}\" references the file
|
||||
\"${file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_FILES_FOR_${target})
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_TARGETS)
|
||||
|
||||
# This file does not depend on other imported targets which have
|
||||
# been exported from the same project but in a separate export set.
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
189
lib/cmake/doctest/doctest.cmake
Normal file
189
lib/cmake/doctest/doctest.cmake
Normal file
@ -0,0 +1,189 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
doctest
|
||||
-----
|
||||
|
||||
This module defines a function to help use the doctest test framework.
|
||||
|
||||
The :command:`doctest_discover_tests` discovers tests by asking the compiled test
|
||||
executable to enumerate its tests. This does not require CMake to be re-run
|
||||
when tests change. However, it may not work in a cross-compiling environment,
|
||||
and setting test properties is less convenient.
|
||||
|
||||
This command is intended to replace use of :command:`add_test` to register
|
||||
tests, and will create a separate CTest test for each doctest test case. Note
|
||||
that this is in some cases less efficient, as common set-up and tear-down logic
|
||||
cannot be shared by multiple test cases executing in the same instance.
|
||||
However, it provides more fine-grained pass/fail information to CTest, which is
|
||||
usually considered as more beneficial. By default, the CTest test name is the
|
||||
same as the doctest name; see also ``TEST_PREFIX`` and ``TEST_SUFFIX``.
|
||||
|
||||
.. command:: doctest_discover_tests
|
||||
|
||||
Automatically add tests with CTest by querying the compiled test executable
|
||||
for available tests::
|
||||
|
||||
doctest_discover_tests(target
|
||||
[TEST_SPEC arg1...]
|
||||
[EXTRA_ARGS arg1...]
|
||||
[WORKING_DIRECTORY dir]
|
||||
[TEST_PREFIX prefix]
|
||||
[TEST_SUFFIX suffix]
|
||||
[PROPERTIES name1 value1...]
|
||||
[ADD_LABELS value]
|
||||
[TEST_LIST var]
|
||||
[JUNIT_OUTPUT_DIR dir]
|
||||
)
|
||||
|
||||
``doctest_discover_tests`` sets up a post-build command on the test executable
|
||||
that generates the list of tests by parsing the output from running the test
|
||||
with the ``--list-test-cases`` argument. This ensures that the full
|
||||
list of tests is obtained. Since test discovery occurs at build time, it is
|
||||
not necessary to re-run CMake when the list of tests changes.
|
||||
However, it requires that :prop_tgt:`CROSSCOMPILING_EMULATOR` is properly set
|
||||
in order to function in a cross-compiling environment.
|
||||
|
||||
Additionally, setting properties on tests is somewhat less convenient, since
|
||||
the tests are not available at CMake time. Additional test properties may be
|
||||
assigned to the set of tests as a whole using the ``PROPERTIES`` option. If
|
||||
more fine-grained test control is needed, custom content may be provided
|
||||
through an external CTest script using the :prop_dir:`TEST_INCLUDE_FILES`
|
||||
directory property. The set of discovered tests is made accessible to such a
|
||||
script via the ``<target>_TESTS`` variable.
|
||||
|
||||
The options are:
|
||||
|
||||
``target``
|
||||
Specifies the doctest executable, which must be a known CMake executable
|
||||
target. CMake will substitute the location of the built executable when
|
||||
running the test.
|
||||
|
||||
``TEST_SPEC arg1...``
|
||||
Specifies test cases, wildcarded test cases, tags and tag expressions to
|
||||
pass to the doctest executable with the ``--list-test-cases`` argument.
|
||||
|
||||
``EXTRA_ARGS arg1...``
|
||||
Any extra arguments to pass on the command line to each test case.
|
||||
|
||||
``WORKING_DIRECTORY dir``
|
||||
Specifies the directory in which to run the discovered test cases. If this
|
||||
option is not provided, the current binary directory is used.
|
||||
|
||||
``TEST_PREFIX prefix``
|
||||
Specifies a ``prefix`` to be prepended to the name of each discovered test
|
||||
case. This can be useful when the same test executable is being used in
|
||||
multiple calls to ``doctest_discover_tests()`` but with different
|
||||
``TEST_SPEC`` or ``EXTRA_ARGS``.
|
||||
|
||||
``TEST_SUFFIX suffix``
|
||||
Similar to ``TEST_PREFIX`` except the ``suffix`` is appended to the name of
|
||||
every discovered test case. Both ``TEST_PREFIX`` and ``TEST_SUFFIX`` may
|
||||
be specified.
|
||||
|
||||
``PROPERTIES name1 value1...``
|
||||
Specifies additional properties to be set on all tests discovered by this
|
||||
invocation of ``doctest_discover_tests``.
|
||||
|
||||
``ADD_LABELS value``
|
||||
Specifies if the test labels should be set automatically.
|
||||
|
||||
``TEST_LIST var``
|
||||
Make the list of tests available in the variable ``var``, rather than the
|
||||
default ``<target>_TESTS``. This can be useful when the same test
|
||||
executable is being used in multiple calls to ``doctest_discover_tests()``.
|
||||
Note that this variable is only available in CTest.
|
||||
|
||||
``JUNIT_OUTPUT_DIR dir``
|
||||
If specified, the parameter is passed along with ``--reporters=junit``
|
||||
and ``--out=`` to the test executable. The actual file name is the same
|
||||
as the test target, including prefix and suffix. This should be used
|
||||
instead of EXTRA_ARGS to avoid race conditions writing the XML result
|
||||
output when using parallel test execution.
|
||||
|
||||
#]=======================================================================]
|
||||
|
||||
#------------------------------------------------------------------------------
|
||||
function(doctest_discover_tests TARGET)
|
||||
cmake_parse_arguments(
|
||||
""
|
||||
""
|
||||
"TEST_PREFIX;TEST_SUFFIX;WORKING_DIRECTORY;TEST_LIST;JUNIT_OUTPUT_DIR"
|
||||
"TEST_SPEC;EXTRA_ARGS;PROPERTIES;ADD_LABELS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
if(NOT _WORKING_DIRECTORY)
|
||||
set(_WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
endif()
|
||||
if(NOT _TEST_LIST)
|
||||
set(_TEST_LIST ${TARGET}_TESTS)
|
||||
endif()
|
||||
|
||||
## Generate a unique name based on the extra arguments
|
||||
string(SHA1 args_hash "${_TEST_SPEC} ${_EXTRA_ARGS}")
|
||||
string(SUBSTRING ${args_hash} 0 7 args_hash)
|
||||
|
||||
# Define rule to generate test list for aforementioned test executable
|
||||
set(ctest_include_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_include-${args_hash}.cmake")
|
||||
set(ctest_tests_file "${CMAKE_CURRENT_BINARY_DIR}/${TARGET}_tests-${args_hash}.cmake")
|
||||
get_property(crosscompiling_emulator
|
||||
TARGET ${TARGET}
|
||||
PROPERTY CROSSCOMPILING_EMULATOR
|
||||
)
|
||||
add_custom_command(
|
||||
TARGET ${TARGET} POST_BUILD
|
||||
BYPRODUCTS "${ctest_tests_file}"
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-D "TEST_TARGET=${TARGET}"
|
||||
-D "TEST_EXECUTABLE=$<TARGET_FILE:${TARGET}>"
|
||||
-D "TEST_EXECUTOR=${crosscompiling_emulator}"
|
||||
-D "TEST_WORKING_DIR=${_WORKING_DIRECTORY}"
|
||||
-D "TEST_SPEC=${_TEST_SPEC}"
|
||||
-D "TEST_EXTRA_ARGS=${_EXTRA_ARGS}"
|
||||
-D "TEST_PROPERTIES=${_PROPERTIES}"
|
||||
-D "TEST_ADD_LABELS=${_ADD_LABELS}"
|
||||
-D "TEST_PREFIX=${_TEST_PREFIX}"
|
||||
-D "TEST_SUFFIX=${_TEST_SUFFIX}"
|
||||
-D "TEST_LIST=${_TEST_LIST}"
|
||||
-D "TEST_JUNIT_OUTPUT_DIR=${_JUNIT_OUTPUT_DIR}"
|
||||
-D "CTEST_FILE=${ctest_tests_file}"
|
||||
-P "${_DOCTEST_DISCOVER_TESTS_SCRIPT}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
file(WRITE "${ctest_include_file}"
|
||||
"if(EXISTS \"${ctest_tests_file}\")\n"
|
||||
" include(\"${ctest_tests_file}\")\n"
|
||||
"else()\n"
|
||||
" add_test(${TARGET}_NOT_BUILT-${args_hash} ${TARGET}_NOT_BUILT-${args_hash})\n"
|
||||
"endif()\n"
|
||||
)
|
||||
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.10)
|
||||
# Add discovered tests to directory TEST_INCLUDE_FILES
|
||||
set_property(DIRECTORY
|
||||
APPEND PROPERTY TEST_INCLUDE_FILES "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
# Add discovered tests as directory TEST_INCLUDE_FILE if possible
|
||||
get_property(test_include_file_set DIRECTORY PROPERTY TEST_INCLUDE_FILE SET)
|
||||
if(NOT ${test_include_file_set})
|
||||
set_property(DIRECTORY
|
||||
PROPERTY TEST_INCLUDE_FILE "${ctest_include_file}"
|
||||
)
|
||||
else()
|
||||
message(FATAL_ERROR
|
||||
"Cannot set more than one TEST_INCLUDE_FILE"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
endfunction()
|
||||
|
||||
###############################################################################
|
||||
|
||||
set(_DOCTEST_DISCOVER_TESTS_SCRIPT
|
||||
${CMAKE_CURRENT_LIST_DIR}/doctestAddTests.cmake
|
||||
)
|
||||
120
lib/cmake/doctest/doctestAddTests.cmake
Normal file
120
lib/cmake/doctest/doctestAddTests.cmake
Normal file
@ -0,0 +1,120 @@
|
||||
# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
# file Copyright.txt or https://cmake.org/licensing for details.
|
||||
|
||||
set(prefix "${TEST_PREFIX}")
|
||||
set(suffix "${TEST_SUFFIX}")
|
||||
set(spec ${TEST_SPEC})
|
||||
set(extra_args ${TEST_EXTRA_ARGS})
|
||||
set(properties ${TEST_PROPERTIES})
|
||||
set(add_labels ${TEST_ADD_LABELS})
|
||||
set(junit_output_dir "${TEST_JUNIT_OUTPUT_DIR}")
|
||||
set(script)
|
||||
set(suite)
|
||||
set(tests)
|
||||
|
||||
function(add_command NAME)
|
||||
set(_args "")
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg MATCHES "[^-./:a-zA-Z0-9_]")
|
||||
set(_args "${_args} [==[${_arg}]==]") # form a bracket_argument
|
||||
else()
|
||||
set(_args "${_args} ${_arg}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(script "${script}${NAME}(${_args})\n" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Run test executable to get list of available tests
|
||||
if(NOT EXISTS "${TEST_EXECUTABLE}")
|
||||
message(FATAL_ERROR
|
||||
"Specified test executable '${TEST_EXECUTABLE}' does not exist"
|
||||
)
|
||||
endif()
|
||||
|
||||
if("${spec}" MATCHES .)
|
||||
set(spec "--test-case=${spec}")
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" ${spec} --list-test-cases
|
||||
OUTPUT_VARIABLE output
|
||||
RESULT_VARIABLE result
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${result} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${result}\n"
|
||||
" Output: ${output}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" output "${output}")
|
||||
|
||||
# Parse output
|
||||
foreach(line ${output})
|
||||
if("${line}" STREQUAL "===============================================================================" OR "${line}" MATCHES [==[^\[doctest\] ]==])
|
||||
continue()
|
||||
endif()
|
||||
set(test ${line})
|
||||
set(labels "")
|
||||
if(${add_labels})
|
||||
# get test suite that test belongs to
|
||||
execute_process(
|
||||
COMMAND ${TEST_EXECUTOR} "${TEST_EXECUTABLE}" --test-case=${test} --list-test-suites
|
||||
OUTPUT_VARIABLE labeloutput
|
||||
RESULT_VARIABLE labelresult
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
)
|
||||
if(NOT ${labelresult} EQUAL 0)
|
||||
message(FATAL_ERROR
|
||||
"Error running test executable '${TEST_EXECUTABLE}':\n"
|
||||
" Result: ${labelresult}\n"
|
||||
" Output: ${labeloutput}\n"
|
||||
)
|
||||
endif()
|
||||
|
||||
string(REPLACE "\n" ";" labeloutput "${labeloutput}")
|
||||
foreach(labelline ${labeloutput})
|
||||
if("${labelline}" STREQUAL "===============================================================================" OR "${labelline}" MATCHES [==[^\[doctest\] ]==])
|
||||
continue()
|
||||
endif()
|
||||
list(APPEND labels ${labelline})
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT "${junit_output_dir}" STREQUAL "")
|
||||
# turn testname into a valid filename by replacing all special characters with "-"
|
||||
string(REGEX REPLACE "[/\\:\"|<>]" "-" test_filename "${test}")
|
||||
set(TEST_JUNIT_OUTPUT_PARAM "--reporters=junit" "--out=${junit_output_dir}/${prefix}${test_filename}${suffix}.xml")
|
||||
else()
|
||||
unset(TEST_JUNIT_OUTPUT_PARAM)
|
||||
endif()
|
||||
# use escape commas to handle properly test cases with commas inside the name
|
||||
string(REPLACE "," "\\," test_name ${test})
|
||||
# ...and add to script
|
||||
add_command(add_test
|
||||
"${prefix}${test}${suffix}"
|
||||
${TEST_EXECUTOR}
|
||||
"${TEST_EXECUTABLE}"
|
||||
"--test-case=${test_name}"
|
||||
"${TEST_JUNIT_OUTPUT_PARAM}"
|
||||
${extra_args}
|
||||
)
|
||||
add_command(set_tests_properties
|
||||
"${prefix}${test}${suffix}"
|
||||
PROPERTIES
|
||||
WORKING_DIRECTORY "${TEST_WORKING_DIR}"
|
||||
${properties}
|
||||
LABELS ${labels}
|
||||
)
|
||||
unset(labels)
|
||||
list(APPEND tests "${prefix}${test}${suffix}")
|
||||
endforeach()
|
||||
|
||||
# Create a list of all discovered tests, which users may use to e.g. set
|
||||
# properties on the tests
|
||||
add_command(set ${TEST_LIST} ${tests})
|
||||
|
||||
# Write CTest script
|
||||
file(WRITE "${CTEST_FILE}" "${script}")
|
||||
6
lib/cmake/doctest/doctestConfig.cmake
Normal file
6
lib/cmake/doctest/doctestConfig.cmake
Normal file
@ -0,0 +1,6 @@
|
||||
if(NOT TARGET doctest::doctest)
|
||||
# Provide path for scripts
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/doctestTargets.cmake")
|
||||
endif()
|
||||
70
lib/cmake/doctest/doctestConfigVersion.cmake
Normal file
70
lib/cmake/doctest/doctestConfigVersion.cmake
Normal file
@ -0,0 +1,70 @@
|
||||
# This is a basic version file for the Config-mode of find_package().
|
||||
# It is used by write_basic_package_version_file() as input file for configure_file()
|
||||
# to create a version-file which can be installed along a config.cmake file.
|
||||
#
|
||||
# The created file sets PACKAGE_VERSION_EXACT if the current version string and
|
||||
# the requested version string are exactly the same and it sets
|
||||
# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version,
|
||||
# but only if the requested major version is the same as the current one.
|
||||
# The variable CVF_VERSION must be set before calling configure_file().
|
||||
|
||||
|
||||
set(PACKAGE_VERSION "2.4.11")
|
||||
|
||||
if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION)
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
|
||||
if("2.4.11" MATCHES "^([0-9]+)\\.")
|
||||
set(CVF_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
if(NOT CVF_VERSION_MAJOR VERSION_EQUAL 0)
|
||||
string(REGEX REPLACE "^0+" "" CVF_VERSION_MAJOR "${CVF_VERSION_MAJOR}")
|
||||
endif()
|
||||
else()
|
||||
set(CVF_VERSION_MAJOR "2.4.11")
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION_RANGE)
|
||||
# both endpoints of the range must have the expected major version
|
||||
math (EXPR CVF_VERSION_MAJOR_NEXT "${CVF_VERSION_MAJOR} + 1")
|
||||
if (NOT PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
|
||||
OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
||||
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND NOT PACKAGE_FIND_VERSION_MAX VERSION_LESS_EQUAL CVF_VERSION_MAJOR_NEXT)))
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
elseif(PACKAGE_FIND_VERSION_MIN_MAJOR STREQUAL CVF_VERSION_MAJOR
|
||||
AND ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS_EQUAL PACKAGE_FIND_VERSION_MAX)
|
||||
OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MAX)))
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
endif()
|
||||
else()
|
||||
if(PACKAGE_FIND_VERSION_MAJOR STREQUAL CVF_VERSION_MAJOR)
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
endif()
|
||||
|
||||
if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION)
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
# if the installed project requested no architecture check, don't perform the check
|
||||
if("FALSE")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "")
|
||||
math(EXPR installedBits " * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
||||
99
lib/cmake/doctest/doctestTargets.cmake
Normal file
99
lib/cmake/doctest/doctestTargets.cmake
Normal file
@ -0,0 +1,99 @@
|
||||
# Generated by CMake
|
||||
|
||||
if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.6)
|
||||
message(FATAL_ERROR "CMake >= 2.6.0 required")
|
||||
endif()
|
||||
cmake_policy(PUSH)
|
||||
cmake_policy(VERSION 2.6...3.21)
|
||||
#----------------------------------------------------------------
|
||||
# Generated CMake target import file.
|
||||
#----------------------------------------------------------------
|
||||
|
||||
# Commands may need to know the format version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION 1)
|
||||
|
||||
# Protect against multiple inclusion, which would fail when already imported targets are added once more.
|
||||
set(_targetsDefined)
|
||||
set(_targetsNotDefined)
|
||||
set(_expectedTargets)
|
||||
foreach(_expectedTarget doctest::doctest)
|
||||
list(APPEND _expectedTargets ${_expectedTarget})
|
||||
if(NOT TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsNotDefined ${_expectedTarget})
|
||||
endif()
|
||||
if(TARGET ${_expectedTarget})
|
||||
list(APPEND _targetsDefined ${_expectedTarget})
|
||||
endif()
|
||||
endforeach()
|
||||
if("${_targetsDefined}" STREQUAL "${_expectedTargets}")
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
return()
|
||||
endif()
|
||||
if(NOT "${_targetsDefined}" STREQUAL "")
|
||||
message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n")
|
||||
endif()
|
||||
unset(_targetsDefined)
|
||||
unset(_targetsNotDefined)
|
||||
unset(_expectedTargets)
|
||||
|
||||
|
||||
# Compute the installation prefix relative to this file.
|
||||
get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH)
|
||||
if(_IMPORT_PREFIX STREQUAL "/")
|
||||
set(_IMPORT_PREFIX "")
|
||||
endif()
|
||||
|
||||
# Create imported target doctest::doctest
|
||||
add_library(doctest::doctest INTERFACE IMPORTED)
|
||||
|
||||
set_target_properties(doctest::doctest PROPERTIES
|
||||
INTERFACE_COMPILE_FEATURES "cxx_std_11"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
|
||||
)
|
||||
|
||||
if(CMAKE_VERSION VERSION_LESS 3.0.0)
|
||||
message(FATAL_ERROR "This file relies on consumers using CMake 3.0.0 or greater.")
|
||||
endif()
|
||||
|
||||
# Load information for each installed configuration.
|
||||
get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||
file(GLOB CONFIG_FILES "${_DIR}/doctestTargets-*.cmake")
|
||||
foreach(f ${CONFIG_FILES})
|
||||
include(${f})
|
||||
endforeach()
|
||||
|
||||
# Cleanup temporary variables.
|
||||
set(_IMPORT_PREFIX)
|
||||
|
||||
# Loop over all imported files and verify that they actually exist
|
||||
foreach(target ${_IMPORT_CHECK_TARGETS} )
|
||||
foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} )
|
||||
if(NOT EXISTS "${file}" )
|
||||
message(FATAL_ERROR "The imported target \"${target}\" references the file
|
||||
\"${file}\"
|
||||
but this file does not exist. Possible reasons include:
|
||||
* The file was deleted, renamed, or moved to another location.
|
||||
* An install or uninstall procedure did not complete successfully.
|
||||
* The installation package was faulty and contained
|
||||
\"${CMAKE_CURRENT_LIST_FILE}\"
|
||||
but not all the files it references.
|
||||
")
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_FILES_FOR_${target})
|
||||
endforeach()
|
||||
unset(_IMPORT_CHECK_TARGETS)
|
||||
|
||||
# This file does not depend on other imported targets which have
|
||||
# been exported from the same project but in a separate export set.
|
||||
|
||||
# Commands beyond this point should not need to know the version.
|
||||
set(CMAKE_IMPORT_FILE_VERSION)
|
||||
cmake_policy(POP)
|
||||
BIN
share/poet/barite/barite_200.qs2
Normal file
BIN
share/poet/barite/barite_200.qs2
Normal file
Binary file not shown.
7
share/poet/barite/barite_200_rt.R
Normal file
7
share/poet/barite/barite_200_rt.R
Normal file
@ -0,0 +1,7 @@
|
||||
iterations <- 50
|
||||
dt <- 100
|
||||
|
||||
list(
|
||||
timesteps = rep(dt, iterations),
|
||||
store_result = TRUE
|
||||
)
|
||||
BIN
share/poet/barite/barite_het.qs2
Normal file
BIN
share/poet/barite/barite_het.qs2
Normal file
Binary file not shown.
4
share/poet/barite/barite_het_rt.R
Normal file
4
share/poet/barite/barite_het_rt.R
Normal file
@ -0,0 +1,4 @@
|
||||
list(
|
||||
timesteps = rep(50, 100),
|
||||
store_result = TRUE
|
||||
)
|
||||
BIN
share/poet/dolo/dolo_inner_large.qs2
Normal file
BIN
share/poet/dolo/dolo_inner_large.qs2
Normal file
Binary file not shown.
10
share/poet/dolo/dolo_inner_large_rt.R
Normal file
10
share/poet/dolo/dolo_inner_large_rt.R
Normal file
@ -0,0 +1,10 @@
|
||||
iterations <- 500
|
||||
dt <- 50
|
||||
|
||||
out_save <- seq(5, iterations, by = 5)
|
||||
|
||||
list(
|
||||
timesteps = rep(dt, iterations),
|
||||
store_result = TRUE,
|
||||
out_save = out_save
|
||||
)
|
||||
BIN
share/poet/dolo/dolo_interp.qs2
Normal file
BIN
share/poet/dolo/dolo_interp.qs2
Normal file
Binary file not shown.
10
share/poet/dolo/dolo_interp_rt.R
Normal file
10
share/poet/dolo/dolo_interp_rt.R
Normal file
@ -0,0 +1,10 @@
|
||||
iterations <- 20000
|
||||
dt <- 200
|
||||
|
||||
out_save <- seq(50, iterations, by = 50)
|
||||
|
||||
list(
|
||||
timesteps = rep(dt, iterations),
|
||||
store_result = TRUE,
|
||||
out_save = out_save
|
||||
)
|
||||
BIN
share/poet/surfex/PoetEGU_surfex_500.qs2
Normal file
BIN
share/poet/surfex/PoetEGU_surfex_500.qs2
Normal file
Binary file not shown.
11
share/poet/surfex/PoetEGU_surfex_500_rt.R
Normal file
11
share/poet/surfex/PoetEGU_surfex_500_rt.R
Normal file
@ -0,0 +1,11 @@
|
||||
iterations <- 200
|
||||
dt <- 1000
|
||||
|
||||
out_save <- c(1, 2, seq(5, iterations, by=5))
|
||||
## out_save <- seq(1, iterations)
|
||||
|
||||
list(
|
||||
timesteps = rep(dt, iterations),
|
||||
store_result = TRUE,
|
||||
out_save = out_save
|
||||
)
|
||||
@ -22,6 +22,7 @@ add_library(POETLib
|
||||
Init/DiffusionInit.cpp
|
||||
Init/ChemistryInit.cpp
|
||||
IO/checkpoint.cpp
|
||||
IO/StatsIO.cpp
|
||||
DataStructures/Field.cpp
|
||||
Transport/DiffusionModule.cpp
|
||||
Chemistry/ChemistryModule.cpp
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user