ritsuko
Helper utilities for ArtifactDB C++ code
Loading...
Searching...
No Matches
validate_string.hpp
Go to the documentation of this file.
1#ifndef RITSUKO_HDF5_VALIDATE_STRING_HPP
2#define RITSUKO_HDF5_VALIDATE_STRING_HPP
3
4#include <string>
5#include <vector>
6#include <stdexcept>
7#include <cassert>
8#include <algorithm>
9
10#include "H5Cpp.h"
12
14#include "IterateChunks.hpp"
15#include "ReclaimVlsMemory.hpp"
16#include "../itoa.hpp"
17
23namespace ritsuko {
24
25namespace hdf5 {
26
36inline void validate_scalar_string(const H5::DataSet& data) {
37 assert(data.getSpace().getSimpleExtentNdims() == 0);
38 assert(data.getDataType().getClass() == H5T_STRING);
39
40 auto dtype = data.getDataType();
41 if (!dtype.isVariableStr()) {
42 return;
43 }
44
45 char* vptr = NULL;
46 data.read(&vptr, dtype);
47
48 const auto& dspace = data.getSpace();
49 const auto& plist = H5::DSetMemXferPropList::DEFAULT;
50 [[maybe_unused]] ReclaimVlsMemory deletor(&dtype, &dspace, &plist, &vptr);
51
52 if (vptr == NULL) {
53 throw std::runtime_error("detected a NULL pointer for a variable length string");
54 }
55}
56
67
79inline void validate_1d_strings(const H5::DataSet& data, hsize_t full_length, const Validate1dStringsOptions& options) {
80 assert(data.getSpace().getSimpleExtentNdims() == 1);
81 assert(data.getDataType().getClass() == H5T_STRING);
82
83 auto dtype = data.getDataType();
84 if (!dtype.isVariableStr()) {
85 return;
86 }
87
88 hsize_t block_size;
89 const auto& plist = data.getCreatePlist();
90 if (plist.getLayout() == H5D_CHUNKED) {
91 plist.getChunk(1, &block_size);
92 } else {
93 block_size = std::min(full_length, options.contiguous_chunk_size);
94 }
95
96 H5::DataSpace mspace(1, &block_size), dspace(1, &full_length);
97 auto buffer = sanisizer::create<std::vector<char*> >(block_size);
98
99 hsize_t pos = 0;
100 while (true) {
101 const hsize_t available = sanisizer::min(full_length - pos, block_size);
102 if (available == 0) {
103 break;
104 }
105
106 constexpr hsize_t zero = 0;
107 mspace.selectHyperslab(H5S_SELECT_SET, &available, &zero);
108 dspace.selectHyperslab(H5S_SELECT_SET, &available, &pos);
109 data.read(buffer.data(), dtype, mspace, dspace);
110
111 const auto& plist = H5::DSetMemXferPropList::DEFAULT;
112 [[maybe_unused]] ReclaimVlsMemory deletor(&dtype, &mspace, &plist, buffer.data());
113 for (hsize_t i = 0; i < available; ++i) {
114 if (buffer[i] == NULL) {
115 throw std::runtime_error("detected a NULL pointer for a variable length string at position " + itoa(pos + i));
116 }
117 }
118
119 pos += available;
120 }
121}
122
133
145inline void validate_nd_strings(const H5::DataSet& data, const std::vector<hsize_t>& dimensions, const ValidateNdStringsOptions& options) {
146 assert(data.getSpace().getSimpleExtentNdims() > 0);
147 assert(data.getDataType().getClass() == H5T_STRING);
148
149 auto stype = data.getDataType();
150 if (!stype.isVariableStr()) {
151 return;
152 }
153
154 // Cast of 'ndims' to 'int' is implicitly safe if the assertion holds.
155 const auto ndims = dimensions.size();
156 assert(sanisizer::is_equal(ndims, data.getSpace().getSimpleExtentNdims()));
157
158 std::vector<hsize_t> chunk_dims;
159 const auto& plist = data.getCreatePlist();
160 if (plist.getLayout() == H5D_CHUNKED) {
161 chunk_dims.resize(ndims); // this is safe as 'dimensions' and 'chunk_dims' have the same size_type.
162 plist.getChunk(dimensions.size(), chunk_dims.data());
163 } else {
164 chunk_dims = mock_contiguous_chunks(dimensions, options.contiguous_chunk_size);
165 }
166
167 IterateChunks iter(dimensions, chunk_dims);
168
169 const auto ndim = dimensions.size();
170 H5::DataSpace fspace(ndim, dimensions.data());
171 H5::DataSpace mspace(ndim, iter.chunk_dimensions().data());
172 auto buffer = sanisizer::create<std::vector<char*> >(mspace.getSimpleExtentNpoints());
173
174 while (iter.advance()) {
175 const auto& curcount = iter.counts();
176 const auto& curstart = iter.starts();
177 mspace.setExtentSimple(ndim, curcount.data());
178 fspace.selectHyperslab(H5S_SELECT_SET, curcount.data(), curstart.data());
179
180 data.read(buffer.data(), stype, mspace, fspace);
181 const auto& plist = H5::DSetMemXferPropList::DEFAULT;
182 [[maybe_unused]] ReclaimVlsMemory deleter(&stype, &mspace, &plist, buffer.data());
183
184 const auto npts = mspace.getSimpleExtentNpoints();
185 for (I<decltype(npts)> i = 0; i < npts; ++i) {
186 if (buffer[i] == NULL) {
187 auto posstr = emit_coordinates_as_string(i, npts, curstart, curcount);
188 throw std::runtime_error("detected NULL pointer for a variable-length string at position " + posstr);
189 }
190 }
191 }
192}
193
203inline void validate_scalar_string(const H5::Attribute& attr) {
204 assert(attr.getSpace().getSimpleExtentNdims() == 0);
205 assert(attr.getDataType().getClass() == H5T_STRING);
206
207 auto dtype = attr.getDataType();
208 if (!dtype.isVariableStr()) {
209 return;
210 }
211
212 const auto& mspace = attr.getSpace();
213 const auto& plist = H5::DSetMemXferPropList::DEFAULT; // yes, even H5Aread uses H5P_DATASET_XFER_DEFAULT.
214 char* buffer;
215 attr.read(dtype, &buffer);
216 [[maybe_unused]] ReclaimVlsMemory deletor(&dtype, &mspace, &plist, &buffer);
217 if (buffer == NULL) {
218 throw std::runtime_error("detected a NULL pointer for a variable length string");
219 }
220}
221
232inline void validate_1d_strings(const H5::Attribute& attr, hsize_t full_length) {
233 assert(attr.getSpace().getSimpleExtentNdims() == 1);
234 assert(attr.getDataType().getClass() == H5T_STRING);
235
236 auto dtype = attr.getDataType();
237 if (!dtype.isVariableStr()) {
238 return;
239 }
240
241 const auto& mspace = attr.getSpace();
242 const auto& plist = H5::DSetMemXferPropList::DEFAULT; // yes, even H5Aread uses H5P_DATASET_XFER_DEFAULT.
243 auto buffer = sanisizer::create<std::vector<char*> >(full_length);
244 attr.read(dtype, buffer.data());
245 [[maybe_unused]] ReclaimVlsMemory deletor(&dtype, &mspace, &plist, buffer.data());
246 for (hsize_t i = 0; i < full_length; ++i) {
247 if (buffer[i] == NULL) {
248 throw std::runtime_error("detected a NULL pointer for a variable length string");
249 }
250 }
251}
252
253}
254
255}
256
257#endif
Iterate through a dataspace by chunk.
Reclaim memory allocated to HDF5's variable length strings.
Reclaim memory for HDF5's variable length strings.
Definition ReclaimVlsMemory.hpp:38
Convert an integer to a string.
Mock chunk sizes for a contiguous HDF5 dataset.
std::vector< hsize_t > mock_contiguous_chunks(const std::vector< hsize_t > &dimensions, hsize_t chunk_size)
Definition mock_contiguous_chunks.hpp:30
void validate_nd_strings(const H5::DataSet &data, const std::vector< hsize_t > &dimensions, const ValidateNdStringsOptions &options)
Definition validate_string.hpp:145
void validate_1d_strings(const H5::DataSet &data, hsize_t full_length, const Validate1dStringsOptions &options)
Definition validate_string.hpp:79
void validate_scalar_string(const H5::DataSet &data)
Definition validate_string.hpp:36
Helper functions for ArtifactDB parsing and validation.
Definition Pointer.hpp:22
void itoa(Integer_ x, std::string &output)
Definition itoa.hpp:26
Container_ create(Value_ x, Args_ &&... args)
constexpr bool is_equal(Left_ left, Right_ right)
constexpr auto min(First_ first, Second_ second)
constexpr Dest_ cap(Value_ x)
Iterate through an high-dimensional dataspace by chunk.
Definition IterateChunks.hpp:29
const std::vector< hsize_t > & chunk_dimensions() const
Definition IterateChunks.hpp:123
bool advance()
Definition IterateChunks.hpp:67
const std::vector< hsize_t > & starts() const
Definition IterateChunks.hpp:96
const std::vector< hsize_t > & counts() const
Definition IterateChunks.hpp:107
Options for validate_1d_strings().
Definition validate_string.hpp:60
hsize_t contiguous_chunk_size
Definition validate_string.hpp:65
Options for validate_nd_strings().
Definition validate_string.hpp:126
hsize_t contiguous_chunk_size
Definition validate_string.hpp:131