HighFive 2.10.0
HighFive - Header-only C++ HDF5 interface
Loading...
Searching...
No Matches
H5Converter_misc.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Blue Brain Project
3 *
4 * Distributed under the Boost Software License, Version 1.0.
5 * (See accompanying file LICENSE_1_0.txt or copy at
6 * http://www.boost.org/LICENSE_1_0.txt)
7 *
8 */
9#pragma once
10
11#include <type_traits>
12
13#include "H5Inspector_misc.hpp"
14#include "../H5DataType.hpp"
15
16namespace HighFive {
17namespace details {
18
19template <class T>
20struct is_std_string {
21 static constexpr bool value =
22 std::is_same<typename inspector<T>::base_type, std::string>::value;
23};
24
25template <class T, class V = void>
26struct enable_shallow_copy
27 : public std::enable_if<!is_std_string<T>::value && inspector<T>::is_trivially_copyable, V> {};
28
29template <class T, class V = void>
30struct enable_deep_copy
31 : public std::enable_if<!is_std_string<T>::value && !inspector<T>::is_trivially_copyable, V> {};
32
33template <class T, class V = void>
34struct enable_string_copy: public std::enable_if<is_std_string<T>::value, V> {};
35
36
37template <typename T, bool IsReadOnly>
38struct ShallowCopyBuffer {
39 using type = unqualified_t<T>;
40 using hdf5_type =
41 typename std::conditional<IsReadOnly,
42 typename std::add_const<typename inspector<T>::hdf5_type>::type,
43 typename inspector<T>::hdf5_type>::type;
44
45 ShallowCopyBuffer() = delete;
46
47 explicit ShallowCopyBuffer(typename std::conditional<IsReadOnly, const T&, T&>::type val)
48 : ptr(inspector<T>::data(val)){};
49
50 hdf5_type* getPointer() const {
51 return ptr;
52 }
53
54 hdf5_type* begin() const {
55 return getPointer();
56 }
57
58 void unserialize(T& /* val */) const {
59 /* nothing to do. */
60 }
61
62 private:
63 hdf5_type* ptr;
64};
65
66template <class T>
67struct DeepCopyBuffer {
68 using type = unqualified_t<T>;
69 using hdf5_type = typename inspector<type>::hdf5_type;
70
71 explicit DeepCopyBuffer(const std::vector<size_t>& _dims)
72 : buffer(inspector<T>::getSize(_dims))
73 , dims(_dims) {}
74
75 hdf5_type* getPointer() {
76 return buffer.data();
77 }
78
79 hdf5_type const* getPointer() const {
80 return buffer.data();
81 }
82
83 hdf5_type* begin() {
84 return getPointer();
85 }
86
87 hdf5_type const* begin() const {
88 return getPointer();
89 }
90
91 void unserialize(T& val) const {
92 inspector<type>::unserialize(buffer.data(), dims, val);
93 }
94
95 private:
96 std::vector<hdf5_type> buffer;
97 std::vector<size_t> dims;
98};
99
100enum class BufferMode { Read, Write };
101
102
106inline size_t char_buffer_size(char const* const str, size_t max_string_length) {
107 for (size_t i = 0; i <= max_string_length; ++i) {
108 if (str[i] == '\0') {
109 return i;
110 }
111 }
112
113 return max_string_length;
114}
115
116
164template <typename T, BufferMode buffer_mode>
165struct StringBuffer {
166 using type = unqualified_t<T>;
167 using hdf5_type = typename inspector<type>::hdf5_type;
168
169 class StringView {
170 public:
171 StringView(StringBuffer<T, buffer_mode>& _buffer, size_t _i)
172 : buffer(_buffer)
173 , i(_i) {}
174
182 void assign(char const* data, size_t length, StringPadding pad) {
183 if (buffer.isVariableLengthString()) {
185 buffer.variable_length_pointers[i] = data;
186 } else {
187 buffer.variable_length_buffer[i] = std::string(data, length);
188 buffer.variable_length_pointers[i] = buffer.variable_length_buffer[i].data();
189 }
190 } else if (buffer.isFixedLengthString()) {
191 // If the buffer is fixed-length and null-terminated, then
192 // `buffer.string_length` doesn't include the null-character.
193 if (length > buffer.string_length) {
194 throw std::invalid_argument("String length too big.");
195 }
196
197 memcpy(&buffer.fixed_length_buffer[i * buffer.string_size], data, length);
198 }
199 }
200
201 private:
202 StringBuffer<T, buffer_mode>& buffer;
203 size_t i;
204 };
205
206
207 class StringConstView {
208 public:
209 StringConstView(const StringBuffer<T, buffer_mode>& _buffer, size_t _i)
210 : buffer(_buffer)
211 , i(_i) {}
212
216 char const* data() const {
217 if (buffer.isVariableLengthString()) {
218 return buffer.variable_length_pointers[i];
219 } else {
220 return &buffer.fixed_length_buffer[i * buffer.string_size];
221 }
222 }
223
230 size_t length() const {
231 if (buffer.isNullTerminated()) {
232 return char_buffer_size(data(), buffer.string_length);
233 } else {
234 return buffer.string_length;
235 }
236 }
237
238 private:
239 const StringBuffer<T, buffer_mode>& buffer;
240 size_t i;
241 };
242
243
244 class Iterator {
245 public:
246 Iterator(StringBuffer<T, buffer_mode>& _buffer, size_t _pos)
247 : buffer(_buffer)
248 , pos(_pos) {}
249
250 Iterator operator+(size_t n_strings) const {
251 return Iterator(buffer, pos + n_strings);
252 }
253
254 void operator+=(size_t n_strings) {
255 pos += n_strings;
256 }
257
258 StringView operator*() {
259 return StringView(buffer, pos);
260 }
261
262 StringConstView operator*() const {
263 return StringConstView(buffer, pos);
264 }
265
266 private:
267 StringBuffer<T, buffer_mode>& buffer;
268 size_t pos;
269 };
270
271 StringBuffer(std::vector<size_t> _dims, const DataType& _file_datatype)
272 : file_datatype(_file_datatype.asStringType())
273 , padding(file_datatype.getPadding())
274 , string_size(file_datatype.isVariableStr() ? size_t(-1) : file_datatype.getSize())
275 , string_length(string_size - size_t(isNullTerminated()))
276 , dims(_dims) {
277 if (string_size == 0 && isNullTerminated()) {
278 throw DataTypeException(
279 "Fixed-length, null-terminated need at least one byte to store the "
280 "null-character.");
281 }
282
283 auto n_strings = compute_total_size(dims);
284 if (isVariableLengthString()) {
285 variable_length_buffer.resize(n_strings);
286 variable_length_pointers.resize(n_strings);
287 } else {
288 char pad = padding == StringPadding::SpacePadded ? ' ' : '\0';
289 fixed_length_buffer.assign(n_strings * string_size, pad);
290 }
291 }
292
293 bool isVariableLengthString() const {
294 return file_datatype.isVariableStr();
295 }
296
297 bool isFixedLengthString() const {
298 return file_datatype.isFixedLenStr();
299 }
300
301 bool isNullTerminated() const {
302 return file_datatype.getPadding() == StringPadding::NullTerminated;
303 }
304
305
306 void* getPointer() {
307 if (file_datatype.isVariableStr()) {
308 return variable_length_pointers.data();
309 } else {
310 return fixed_length_buffer.data();
311 }
312 }
313
314 Iterator begin() {
315 return Iterator(*this, 0ul);
316 }
317
318 void unserialize(T& val) {
319 inspector<type>::unserialize(begin(), dims, val);
320 }
321
322 private:
323 StringType file_datatype;
324 StringPadding padding;
325 size_t string_size; // Size of buffer required to store the string.
326 // Meaningful for fixed length strings only.
327 size_t string_length; // Semantic length of string.
328 std::vector<size_t> dims;
329
330 std::vector<char> fixed_length_buffer;
331 std::vector<std::string> variable_length_buffer;
332 std::vector<
333 typename std::conditional<buffer_mode == BufferMode::Write, const char, char>::type*>
334 variable_length_pointers;
335};
336
337
338template <typename T, typename Enable = void>
339struct Writer;
340
341template <typename T>
342struct Writer<T, typename enable_shallow_copy<T>::type>: public ShallowCopyBuffer<T, true> {
343 private:
344 using super = ShallowCopyBuffer<T, true>;
345
346 public:
347 explicit Writer(const T& val, const DataType& /* file_datatype */)
348 : super(val){};
349};
350
351template <typename T>
352struct Writer<T, typename enable_deep_copy<T>::type>: public DeepCopyBuffer<T> {
353 explicit Writer(const T& val, const DataType& /* file_datatype */)
354 : DeepCopyBuffer<T>(inspector<T>::getDimensions(val)) {
355 inspector<T>::serialize(val, this->begin());
356 }
357};
358
359template <typename T>
360struct Writer<T, typename enable_string_copy<T>::type>: public StringBuffer<T, BufferMode::Write> {
361 explicit Writer(const T& val, const DataType& _file_datatype)
362 : StringBuffer<T, BufferMode::Write>(inspector<T>::getDimensions(val), _file_datatype) {
363 inspector<T>::serialize(val, this->begin());
364 }
365};
366
367template <typename T, typename Enable = void>
368struct Reader;
369
370template <typename T>
371struct Reader<T, typename enable_shallow_copy<T>::type>: public ShallowCopyBuffer<T, false> {
372 private:
373 using super = ShallowCopyBuffer<T, false>;
374 using type = typename super::type;
375
376 public:
377 Reader(const std::vector<size_t>&, type& val, const DataType& /* file_datatype */)
378 : super(val) {}
379};
380
381template <typename T>
382struct Reader<T, typename enable_deep_copy<T>::type>: public DeepCopyBuffer<T> {
383 private:
384 using super = DeepCopyBuffer<T>;
385 using type = typename super::type;
386
387 public:
388 Reader(const std::vector<size_t>& _dims, type&, const DataType& /* file_datatype */)
389 : super(_dims) {}
390};
391
392
393template <typename T>
394struct Reader<T, typename enable_string_copy<T>::type>: public StringBuffer<T, BufferMode::Write> {
395 public:
396 explicit Reader(const std::vector<size_t>& _dims,
397 const T& /* val */,
398 const DataType& _file_datatype)
399 : StringBuffer<T, BufferMode::Write>(_dims, _file_datatype) {}
400};
401
402struct data_converter {
403 template <typename T>
404 static Writer<T> serialize(const typename inspector<T>::type& val,
405 const DataType& file_datatype) {
406 return Writer<T>(val, file_datatype);
407 }
408
409 template <typename T>
410 static Reader<T> get_reader(const std::vector<size_t>& dims,
411 T& val,
412 const DataType& file_datatype) {
413 // TODO Use bufferinfo for recursive_ndim
414 auto effective_dims = details::squeezeDimensions(dims, inspector<T>::recursive_ndim);
415 inspector<T>::prepare(val, effective_dims);
416 return Reader<T>(effective_dims, val, file_datatype);
417 }
418};
419
420} // namespace details
421} // namespace HighFive
size_t getSize(const File &file, const std::string &path)
Get the size of an existing DataSet in an open HDF5 file.
Definition H5Easy_public.hpp:82
Definition H5_definitions.hpp:22
StringPadding
Definition string_padding.hpp:7
size_t compute_total_size(const std::vector< size_t > &dims)
Definition H5Inspector_decl.hpp:10