HighFive 2.3.1
HighFive - Header-only C++ HDF5 interface
Loading...
Searching...
No Matches
H5Converter_misc.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c), 2017, Adrien Devresse <adrien.devresse@epfl.ch>
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#ifndef H5CONVERTER_MISC_HPP
10#define H5CONVERTER_MISC_HPP
11
12#include <algorithm>
13#include <cassert>
14#include <functional>
15#include <numeric>
16#include <sstream>
17#include <string>
18#include <array>
19
20#ifdef H5_USE_BOOST
21// starting Boost 1.64, serialization header must come before ublas
22#include <boost/serialization/vector.hpp>
23#include <boost/multi_array.hpp>
24#include <boost/numeric/ublas/matrix.hpp>
25#endif
26
27#include <H5Dpublic.h>
28#include <H5Ppublic.h>
29
30#include "../H5Reference.hpp"
31#include "H5Utils.hpp"
32
33namespace HighFive {
34
35namespace details {
36
37inline bool is_1D(const std::vector<size_t>& dims) {
38 return std::count_if(dims.begin(), dims.end(), [](size_t i){ return i > 1; }) < 2;
39}
40
41inline size_t compute_total_size(const std::vector<size_t>& dims) {
42 return std::accumulate(dims.begin(), dims.end(), size_t{1u},
43 std::multiplies<size_t>());
44}
45
46inline void check_dimensions_vector(size_t size_vec, size_t size_dataset,
47 size_t dimension) {
48 if (size_vec != size_dataset) {
49 std::ostringstream ss;
50 ss << "Mismatch between vector size (" << size_vec
51 << ") and dataset size (" << size_dataset;
52 ss << ") on dimension " << dimension;
53 throw DataSetException(ss.str());
54 }
55}
56
57
58// Buffer converters
59// =================
60
61// copy multi dimensional vector in C++ in one C-style multi dimensional buffer
62template <typename T>
63inline void vectors_to_single_buffer(const std::vector<T>& vec_single_dim,
64 const std::vector<size_t>& dims,
65 const size_t current_dim,
66 std::vector<T>& buffer) {
67
68 check_dimensions_vector(vec_single_dim.size(), dims[current_dim], current_dim);
69 buffer.insert(buffer.end(), vec_single_dim.begin(), vec_single_dim.end());
70}
71
72
73template <typename T, typename U = typename inspector<T>::base_type>
74inline void
75vectors_to_single_buffer(const std::vector<T>& vec_multi_dim,
76 const std::vector<size_t>& dims,
77 size_t current_dim,
78 std::vector<U>& buffer) {
79
80 check_dimensions_vector(vec_multi_dim.size(), dims[current_dim], current_dim);
81 for (const auto& it : vec_multi_dim) {
82 vectors_to_single_buffer(it, dims, current_dim + 1, buffer);
83 }
84}
85
86// copy single buffer to multi dimensional vector, following specified dimensions
87template <typename T>
88inline typename std::vector<T>::const_iterator
89single_buffer_to_vectors(typename std::vector<T>::const_iterator begin_buffer,
90 typename std::vector<T>::const_iterator end_buffer,
91 const std::vector<size_t>& dims,
92 const size_t current_dim,
93 std::vector<T>& vec_single_dim) {
94 const auto n_elems = static_cast<long>(dims[current_dim]);
95 const auto end_copy_iter = std::min(begin_buffer + n_elems, end_buffer);
96 vec_single_dim.assign(begin_buffer, end_copy_iter);
97 return end_copy_iter;
98}
99
100template <typename T, typename U = typename inspector<T>::base_type>
101inline typename std::vector<U>::const_iterator
102single_buffer_to_vectors(typename std::vector<U>::const_iterator begin_buffer,
103 typename std::vector<U>::const_iterator end_buffer,
104 const std::vector<size_t>& dims,
105 const size_t current_dim,
106 std::vector<std::vector<T>>& vec_multi_dim) {
107 const size_t n_elems = dims[current_dim];
108 vec_multi_dim.resize(n_elems);
109
110 for (auto& subvec : vec_multi_dim) {
111 begin_buffer = single_buffer_to_vectors(
112 begin_buffer, end_buffer, dims, current_dim + 1, subvec);
113 }
114 return begin_buffer;
115}
116
117
118// DATA CONVERTERS
119// ===============
120
121// apply conversion operations to basic scalar type
122template <typename Scalar, class Enable>
123struct data_converter {
124 inline data_converter(const DataSpace&) noexcept {
125
126 static_assert((std::is_arithmetic<Scalar>::value ||
127 std::is_enum<Scalar>::value ||
128 std::is_same<std::string, Scalar>::value),
129 "supported datatype should be an arithmetic value, a "
130 "std::string or a container/array");
131 }
132
133 inline Scalar* transform_read(Scalar& datamem) const noexcept {
134 return &datamem;
135 }
136
137 inline const Scalar* transform_write(const Scalar& datamem) const noexcept {
138 return &datamem;
139 }
140
141 inline void process_result(Scalar&) const noexcept {}
142};
143
144
145// apply conversion operations to the incoming data
146// if they are a cstyle array
147template <typename CArray>
148struct data_converter<CArray,
149 typename std::enable_if<(is_c_array<CArray>::value)>::type> {
150 inline data_converter(const DataSpace&) noexcept {}
151
152 inline CArray& transform_read(CArray& datamem) const noexcept {
153 return datamem;
154 }
155
156 inline const CArray& transform_write(const CArray& datamem) const noexcept {
157 return datamem;
158 }
159
160 inline void process_result(CArray&) const noexcept {}
161};
162
163// Generic container converter
164template <typename Container, typename T = typename inspector<Container>::base_type>
165struct container_converter {
166 typedef T value_type;
167
168 inline container_converter(const DataSpace& space)
169 : _space(space) {}
170
171 // Ship (pseudo)1D implementation
172 inline value_type* transform_read(Container& vec) const {
173 auto&& dims = _space.getDimensions();
174 if (!is_1D(dims))
175 throw DataSpaceException("Dataset cant be converted to 1D");
176 vec.resize(compute_total_size(dims));
177 return vec.data();
178 }
179
180 inline const value_type* transform_write(const Container& vec) const noexcept {
181 return vec.data();
182 }
183
184 inline void process_result(Container&) const noexcept {}
185
186 const DataSpace& _space;
187};
188
189
190// apply conversion for vectors 1D
191template <typename T>
192struct data_converter<
193 std::vector<T>,
194 typename std::enable_if<(
195 std::is_same<T, typename inspector<T>::base_type>::value &&
196 !std::is_same<T, Reference>::value
197 )>::type>
198 : public container_converter<std::vector<T>> {
199
200 using container_converter<std::vector<T>>::container_converter;
201};
202
203
204// apply conversion to std::array
205template <typename T, std::size_t S>
206struct data_converter<
207 std::array<T, S>,
208 typename std::enable_if<(
209 std::is_same<T, typename inspector<T>::base_type>::value)>::type>
210 : public container_converter<std::array<T, S>> {
211
212 inline data_converter(const DataSpace& space)
213 : container_converter<std::array<T, S>>(space)
214 {
215 auto&& dims = space.getDimensions();
216 if (!is_1D(dims)) {
217 throw DataSpaceException("Only 1D std::array supported currently.");
218 }
219 if (compute_total_size(dims) != S) {
220 std::ostringstream ss;
221 ss << "Impossible to pair DataSet with " << compute_total_size(dims)
222 << " elements into an array with " << S << " elements.";
223 throw DataSpaceException(ss.str());
224 }
225 }
226
227 inline T* transform_read(std::array<T, S>& vec) const noexcept {
228 return vec.data();
229 }
230};
231
232
233#ifdef H5_USE_BOOST
234// apply conversion to boost multi array
235template <typename T, std::size_t Dims>
236struct data_converter<boost::multi_array<T, Dims>, void>
237 : public container_converter<boost::multi_array<T, Dims>> {
238 using MultiArray = boost::multi_array<T, Dims>;
239 using value_type = typename inspector<T>::base_type;
240 using container_converter<MultiArray>::container_converter;
241
242 inline value_type* transform_read(MultiArray& array) {
243 auto&& dims = this->_space.getDimensions();
244 if (std::equal(dims.begin(), dims.end(), array.shape()) == false) {
245 boost::array<typename MultiArray::index, Dims> ext;
246 std::copy(dims.begin(), dims.end(), ext.begin());
247 array.resize(ext);
248 }
249 return array.data();
250 }
251};
252
253
254// apply conversion to boost matrix ublas
255template <typename T>
256struct data_converter<boost::numeric::ublas::matrix<T>, void>
257 : public container_converter<boost::numeric::ublas::matrix<T>> {
258 using Matrix = boost::numeric::ublas::matrix<T>;
259 using value_type = typename inspector<T>::base_type;
260
261 inline data_converter(const DataSpace& space) : container_converter<Matrix>(space) {
262 assert(space.getDimensions().size() == 2);
263 }
264
265 inline value_type* transform_read(Matrix& array) {
266 boost::array<std::size_t, 2> sizes = {{array.size1(), array.size2()}};
267 auto&& _dims = this->_space.getDimensions();
268 if (std::equal(_dims.begin(), _dims.end(), sizes.begin()) == false) {
269 array.resize(_dims[0], _dims[1], false);
270 array(0, 0) = 0; // force initialization
271 }
272 return &(array(0, 0));
273 }
274
275 inline const value_type* transform_write(const Matrix& array) const noexcept {
276 return &(array(0, 0));
277 }
278};
279#endif
280
281
282// apply conversion for vectors nested vectors
283template <typename T>
284struct data_converter<std::vector<T>,
285 typename std::enable_if<(is_container<T>::value)>::type> {
286 using value_type = typename inspector<T>::base_type;
287
288 inline data_converter(const DataSpace& space)
289 : _dims(space.getDimensions()) {}
290
291 inline value_type* transform_read(std::vector<T>&) {
292 _vec_align.resize(compute_total_size(_dims));
293 return _vec_align.data();
294 }
295
296 inline const value_type* transform_write(const std::vector<T>& vec) {
297 _vec_align.reserve(compute_total_size(_dims));
298 vectors_to_single_buffer<T>(vec, _dims, 0, _vec_align);
299 return _vec_align.data();
300 }
301
302 inline void process_result(std::vector<T>& vec) const {
303 single_buffer_to_vectors(
304 _vec_align.cbegin(), _vec_align.cend(), _dims, 0, vec);
305 }
306
307 std::vector<size_t> _dims;
308 std::vector<typename inspector<T>::base_type> _vec_align;
309};
310
311
312// apply conversion to scalar string
313template <>
314struct data_converter<std::string, void> {
315 using value_type = const char*; // char data is const, mutable pointer
316
317 inline data_converter(const DataSpace& space) noexcept
318 : _c_vec(nullptr)
319 , _space(space) {}
320
321 // create a C vector adapted to HDF5
322 // fill last element with NULL to identify end
323 inline value_type* transform_read(std::string&) noexcept {
324 return &_c_vec;
325 }
326
327 inline const value_type* transform_write(const std::string& str) noexcept {
328 _c_vec = str.c_str();
329 return &_c_vec;
330 }
331
332 inline void process_result(std::string& str) {
333 assert(_c_vec != nullptr);
334 str = std::string(_c_vec);
335
336 if (_c_vec != nullptr) {
337 AtomicType<std::string> str_type;
338 (void)H5Dvlen_reclaim(str_type.getId(), _space.getId(), H5P_DEFAULT,
339 &_c_vec);
340 }
341 }
342
343 value_type _c_vec;
344 const DataSpace& _space;
345};
346
347// apply conversion for vectors of string (dereference)
348template <>
349struct data_converter<std::vector<std::string>, void> {
350 using value_type = const char*;
351
352 inline data_converter(const DataSpace& space) noexcept
353 : _space(space) {}
354
355 // create a C vector adapted to HDF5
356 // fill last element with NULL to identify end
357 inline value_type* transform_read(std::vector<std::string>&) {
358 _c_vec.resize(_space.getDimensions()[0], NULL);
359 return _c_vec.data();
360 }
361
362 inline const value_type* transform_write(const std::vector<std::string>& vec) {
363 _c_vec.resize(vec.size() + 1, NULL);
364 std::transform(vec.begin(), vec.end(), _c_vec.begin(),
365 [](const std::string& str){ return str.c_str(); });
366 return _c_vec.data();
367 }
368
369 inline void process_result(std::vector<std::string>& vec) {
370 vec.resize(_c_vec.size());
371 for (size_t i = 0; i < vec.size(); ++i) {
372 vec[i] = std::string(_c_vec[i]);
373 }
374
375 if (_c_vec.empty() == false && _c_vec[0] != NULL) {
376 AtomicType<std::string> str_type;
377 (void)H5Dvlen_reclaim(str_type.getId(), _space.getId(), H5P_DEFAULT,
378 &(_c_vec[0]));
379 }
380 }
381
382 std::vector<value_type> _c_vec;
383 const DataSpace& _space;
384};
385
386
387
388// apply conversion for fixed-string. Implements container interface
389template <std::size_t N>
390struct data_converter<FixedLenStringArray<N>, void>
391 : public container_converter<FixedLenStringArray<N>, char> {
392 using container_converter<FixedLenStringArray<N>, char>::container_converter;
393};
394
395template <>
396struct data_converter<std::vector<Reference>, void> {
397 inline data_converter(const DataSpace& space)
398 : _dims(space.getDimensions()) {
399 if (!is_1D(_dims)) {
400 throw DataSpaceException("Only 1D std::array supported currently.");
401 }
402 }
403
404 inline hobj_ref_t* transform_read(std::vector<Reference>& vec) {
405 auto total_size = compute_total_size(_dims);
406 _vec_align.resize(total_size);
407 vec.resize(total_size);
408 return _vec_align.data();
409 }
410
411 inline const hobj_ref_t* transform_write(const std::vector<Reference>& vec) {
412 _vec_align.resize(compute_total_size(_dims));
413 for (size_t i = 0; i < vec.size(); ++i) {
414 vec[i].create_ref(&_vec_align[i]);
415 }
416 return _vec_align.data();
417 }
418
419 inline void process_result(std::vector<Reference>& vec) const {
420 auto* href = const_cast<hobj_ref_t*>(_vec_align.data());
421 for (auto& ref : vec) {
422 ref = Reference(*(href++));
423 }
424 }
425
426 std::vector<size_t> _dims;
427 std::vector<typename inspector<hobj_ref_t>::base_type> _vec_align;
428};
429
430} // namespace details
431
432} // namespace HighFive
433
434#ifdef H5_USE_EIGEN
436#endif
437
438#endif // H5CONVERTER_MISC_HPP
Definition H5_definitions.hpp:15