H5SingleDataReader.hpp
3.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#pragma once
#include <algorithm>
#include <array>
#include <cassert>
#include <memory>
#include <mutex>
#include <numeric>
#include <string>
#include <H5Cpp.h>
/*
* HDF5 C++ API doesn't support multiple threads, even instantiation of types
* since it uses global structres.
*
* Thus, to avoid deafult construction of member H5 types, they are stored using
* not owning pointers.
*/
class H5SingleDataReader {
public:
H5SingleDataReader(const H5SingleDataReader &) = delete;
H5SingleDataReader &operator=(const H5SingleDataReader &) = delete;
H5SingleDataReader(H5SingleDataReader &&) noexcept = default;
H5SingleDataReader &operator=(H5SingleDataReader &&) noexcept = default;
std::array<hsize_t, 3> dimensions{0, 0, 0};
H5SingleDataReader(const std::string &path, const std::string &dataSetPath,
const H5::PredType &dataType, int outputDimension) {
std::lock_guard<std::mutex> guard(lock);
type.reset(assign(dataType));
const H5::H5File file(path, H5F_ACC_RDONLY);
dataSet.reset(assign(file.openDataSet(dataSetPath)));
fileSpace.reset(assign(dataSet->getSpace()));
[[maybe_unused]] const auto rank =
fileSpace->getSimpleExtentDims(dimensions.data(), nullptr);
assert(outputDimension <= rank);
const std::array<hsize_t, 1> memoryDimensions{std::accumulate(
dimensions.cbegin(), dimensions.cbegin() + outputDimension, 1LLU,
std::multiplies<>())};
const std::array<hsize_t, 1> memoryOffset{0};
memorySpace.reset(assign(H5::DataSpace(1, memoryDimensions.data())));
memorySpace->selectHyperslab(H5S_SELECT_SET, memoryDimensions.data(),
memoryOffset.data());
totalSize = memorySpace->getSelectNpoints();
}
hsize_t size() const { return totalSize; }
void read(void *buffer) const {
std::lock_guard<std::mutex> guard(lock);
dataSet->read(buffer, *type, *memorySpace, *fileSpace);
}
void select(const std::array<hsize_t, 3> selectionSize,
const std::array<hsize_t, 3> selectionOffset) const {
std::lock_guard<std::mutex> guard(lock);
fileSpace->selectHyperslab(H5S_SELECT_SET, selectionSize.data(),
selectionOffset.data());
}
virtual ~H5SingleDataReader() {
std::lock_guard<std::mutex> guard(lock);
delete memorySpace.get();
delete fileSpace.get();
delete dataSet.get();
delete type.get();
}
const static H5::PredType UINT8;
const static H5::PredType UINT16;
const static H5::PredType UINT32;
const static H5::PredType UINT64;
const static H5::PredType INT8;
const static H5::PredType INT16;
const static H5::PredType INT32;
const static H5::PredType INT64;
const static H5::PredType FLOAT;
const static H5::PredType DOUBLE;
private:
static std::mutex lock;
hsize_t totalSize;
struct NoOp {
template <typename T> void operator()(T const &) const noexcept {}
};
/**
* not_owning_ptr allows to use default move constructor
* and manually manage target memory
*/
template <typename T> using not_owning_ptr = std::unique_ptr<T, NoOp>;
not_owning_ptr<const H5::PredType> type;
not_owning_ptr<const H5::DataSet> dataSet;
not_owning_ptr<const H5::DataSpace> fileSpace;
not_owning_ptr<const H5::DataSpace> memorySpace;
template <typename T> static const T *assign(const T &value) {
T *const result = new T(value);
*result = value;
return result;
}
};