hops
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 
33 namespace HighFive {
34 
35 namespace details {
36 
37 inline 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 
41 inline 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 
46 inline 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
62 template <typename T>
63 inline 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 
73 template <typename T, typename U = typename type_of_array<T>::type>
74 inline void
75 vectors_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
87 template <typename T>
88 inline typename std::vector<T>::const_iterator
89 single_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 
100 template <typename T, typename U = typename type_of_array<T>::type>
101 inline typename std::vector<U>::const_iterator
102 single_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
122 template <typename Scalar, class Enable>
123 struct 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
147 template <typename CArray>
148 struct 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
164 template <typename Container, typename T = typename type_of_array<Container>::type>
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 
187 };
188 
189 
190 // apply conversion for vectors 1D
191 template <typename T>
193  std::vector<T>,
194  typename std::enable_if<(
195  std::is_same<T, typename type_of_array<T>::type>::value &&
196  !std::is_same<T, Reference>::value
197  )>::type>
198  : public container_converter<std::vector<T>> {
199 
201 };
202 
203 
204 // apply conversion to std::array
205 template <typename T, std::size_t S>
207  std::array<T, S>,
208  typename std::enable_if<(
209  std::is_same<T, typename type_of_array<T>::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
235 template <typename T, std::size_t Dims>
236 struct 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 type_of_array<T>::type;
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
255 template <typename T>
256 struct 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 type_of_array<T>::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
283 template <typename T>
284 struct data_converter<std::vector<T>,
285  typename std::enable_if<(is_container<T>::value)>::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 {
304  _vec_align.cbegin(), _vec_align.cend(), _dims, 0, vec);
305  }
306 
307  std::vector<size_t> _dims;
308  std::vector<typename type_of_array<T>::type> _vec_align;
309 };
310 
311 
312 // apply conversion to scalar string
313 template <>
314 struct 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 
345 };
346 
347 // apply conversion for vectors of string (dereference)
348 template <>
349 struct 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;
384 };
385 
386 
387 
388 // apply conversion for fixed-string. Implements container interface
389 template <std::size_t N>
391  : public container_converter<FixedLenStringArray<N>, char> {
393 };
394 
395 template <>
396 struct 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.reserve(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 type_of_array<hobj_ref_t>::type> _vec_align;
428 };
429 
430 } // namespace details
431 
432 } // namespace HighFive
433 
434 #ifdef H5_USE_EIGEN
435 #include "H5ConverterEigen_misc.hpp"
436 #endif
437 
438 #endif // H5CONVERTER_MISC_HPP
H5ConverterEigen_misc.hpp
HighFive::details::data_converter< std::vector< std::string >, void >::_space
const DataSpace & _space
Definition: H5Converter_misc.hpp:383
HighFive::Reference
An HDF5 (object) reference type.
Definition: H5Reference.hpp:31
HighFive::details::data_converter< std::string, void >::_space
const DataSpace & _space
Definition: H5Converter_misc.hpp:344
HighFive::details::compute_total_size
size_t compute_total_size(const std::vector< size_t > &dims)
Definition: H5Converter_misc.hpp:41
HighFive::details::container_converter::value_type
T value_type
Definition: H5Converter_misc.hpp:166
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::transform_read
value_type * transform_read(std::vector< T > &)
Definition: H5Converter_misc.hpp:291
HighFive::DataSpace::getDimensions
std::vector< size_t > getDimensions() const
getDimensions
Definition: H5Dataspace_misc.hpp:99
size_dataset
const size_t size_dataset
Definition: read_write_vector_dataset.cpp:21
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::_vec_align
std::vector< typename type_of_array< T >::type > _vec_align
Definition: H5Converter_misc.hpp:308
HighFive::details::data_converter< CArray, typename std::enable_if<(is_c_array< CArray >::value)>::type >::transform_read
CArray & transform_read(CArray &datamem) const noexcept
Definition: H5Converter_misc.hpp:152
HighFive::details::data_converter< std::vector< std::string >, void >::process_result
void process_result(std::vector< std::string > &vec)
Definition: H5Converter_misc.hpp:369
HighFive::details::data_converter< CArray, typename std::enable_if<(is_c_array< CArray >::value)>::type >::process_result
void process_result(CArray &) const noexcept
Definition: H5Converter_misc.hpp:160
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::process_result
void process_result(std::vector< T > &vec) const
Definition: H5Converter_misc.hpp:302
HighFive::details::data_converter< std::vector< Reference >, void >::_dims
std::vector< size_t > _dims
Definition: H5Converter_misc.hpp:426
HighFive::details::single_buffer_to_vectors
std::vector< T >::const_iterator single_buffer_to_vectors(typename std::vector< T >::const_iterator begin_buffer, typename std::vector< T >::const_iterator end_buffer, const std::vector< size_t > &dims, const size_t current_dim, std::vector< T > &vec_single_dim)
Definition: H5Converter_misc.hpp:89
HighFive::details::data_converter< std::vector< std::string >, void >::transform_write
const value_type * transform_write(const std::vector< std::string > &vec)
Definition: H5Converter_misc.hpp:362
HighFive::details::data_converter< std::vector< std::string >, void >::data_converter
data_converter(const DataSpace &space) noexcept
Definition: H5Converter_misc.hpp:352
HighFive::details::data_converter::transform_write
const Scalar * transform_write(const Scalar &datamem) const noexcept
Definition: H5Converter_misc.hpp:137
HighFive::details::data_converter< std::string, void >::transform_write
const value_type * transform_write(const std::string &str) noexcept
Definition: H5Converter_misc.hpp:327
HighFive::details::data_converter< CArray, typename std::enable_if<(is_c_array< CArray >::value)>::type >::transform_write
const CArray & transform_write(const CArray &datamem) const noexcept
Definition: H5Converter_misc.hpp:156
HighFive::details::container_converter::_space
const DataSpace & _space
Definition: H5Converter_misc.hpp:186
HighFive::FixedLenStringArray
A structure representing a set of fixed-length strings.
Definition: H5_definitions.hpp:42
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::transform_write
const value_type * transform_write(const std::vector< T > &vec)
Definition: H5Converter_misc.hpp:296
HighFive::details::data_converter< std::vector< Reference >, void >::transform_write
const hobj_ref_t * transform_write(const std::vector< Reference > &vec)
Definition: H5Converter_misc.hpp:411
HighFive::details::container_converter
Definition: H5Converter_misc.hpp:165
HighFive::details::data_converter< std::vector< std::string >, void >::_c_vec
std::vector< value_type > _c_vec
Definition: H5Converter_misc.hpp:382
HighFive::details::data_converter< std::string, void >::value_type
const char * value_type
Definition: H5Converter_misc.hpp:315
HighFive::details::data_converter< std::string, void >::process_result
void process_result(std::string &str)
Definition: H5Converter_misc.hpp:332
HighFive::details::vectors_to_single_buffer
void vectors_to_single_buffer(const std::vector< T > &vec_single_dim, const std::vector< size_t > &dims, const size_t current_dim, std::vector< T > &buffer)
Definition: H5Converter_misc.hpp:63
HighFive::details::data_converter< std::array< T, S >, typename std::enable_if<(std::is_same< T, typename type_of_array< T >::type >::value)>::type >::transform_read
T * transform_read(std::array< T, S > &vec) const noexcept
Definition: H5Converter_misc.hpp:227
HighFive::details::data_converter::process_result
void process_result(Scalar &) const noexcept
Definition: H5Converter_misc.hpp:141
HighFive::details::data_converter::data_converter
data_converter(const DataSpace &) noexcept
Definition: H5Converter_misc.hpp:124
HighFive::details::data_converter< std::array< T, S >, typename std::enable_if<(std::is_same< T, typename type_of_array< T >::type >::value)>::type >::data_converter
data_converter(const DataSpace &space)
Definition: H5Converter_misc.hpp:212
HighFive::DataSetException
Exception specific to HighFive DataSet interface.
Definition: H5Exception.hpp:115
HighFive::details::data_converter< std::vector< Reference >, void >::process_result
void process_result(std::vector< Reference > &vec) const
Definition: H5Converter_misc.hpp:419
HighFive::details::data_converter< std::vector< Reference >, void >::data_converter
data_converter(const DataSpace &space)
Definition: H5Converter_misc.hpp:397
HighFive::details::data_converter< std::string, void >::_c_vec
value_type _c_vec
Definition: H5Converter_misc.hpp:343
HighFive::AtomicType
create an HDF5 DataType from a C++ type
Definition: H5_definitions.hpp:36
HighFive::details::container_converter::process_result
void process_result(Container &) const noexcept
Definition: H5Converter_misc.hpp:184
HighFive::details::is_1D
bool is_1D(const std::vector< size_t > &dims)
Definition: H5Converter_misc.hpp:37
HighFive::details::type_of_array::type
unqualified_t< T > type
Definition: H5Utils.hpp:137
HighFive::details::data_converter::transform_read
Scalar * transform_read(Scalar &datamem) const noexcept
Definition: H5Converter_misc.hpp:133
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::data_converter
data_converter(const DataSpace &space)
Definition: H5Converter_misc.hpp:288
HighFive::details::data_converter< CArray, typename std::enable_if<(is_c_array< CArray >::value)>::type >::data_converter
data_converter(const DataSpace &) noexcept
Definition: H5Converter_misc.hpp:150
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::_dims
std::vector< size_t > _dims
Definition: H5Converter_misc.hpp:307
HighFive::details::check_dimensions_vector
void check_dimensions_vector(size_t size_vec, size_t size_dataset, size_t dimension)
Definition: H5Converter_misc.hpp:46
copy
free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to copy
Definition: LICENSE.txt:6
HighFive::details::data_converter< std::string, void >::data_converter
data_converter(const DataSpace &space) noexcept
Definition: H5Converter_misc.hpp:317
HighFive::DataSpace
Class representing the space (dimensions) of a dataset.
Definition: H5DataSpace.hpp:37
string
NAME string(REPLACE ".cpp" "_bin" example_name ${example_filename}) if($
Definition: hops/Third-party/HighFive/src/examples/CMakeLists.txt:6
HighFive::details::container_converter::transform_write
const value_type * transform_write(const Container &vec) const noexcept
Definition: H5Converter_misc.hpp:180
HighFive::details::data_converter< std::vector< Reference >, void >::transform_read
hobj_ref_t * transform_read(std::vector< Reference > &vec)
Definition: H5Converter_misc.hpp:404
HighFive::details::data_converter< std::vector< T >, typename std::enable_if<(is_container< T >::value)>::type >::value_type
typename type_of_array< T >::type value_type
Definition: H5Converter_misc.hpp:286
HighFive::details::container_converter::transform_read
value_type * transform_read(Container &vec) const
Definition: H5Converter_misc.hpp:172
HighFive::details::data_converter< std::vector< std::string >, void >::value_type
const char * value_type
Definition: H5Converter_misc.hpp:350
HighFive::details::container_converter::container_converter
container_converter(const DataSpace &space)
Definition: H5Converter_misc.hpp:168
HighFive::details::data_converter< std::string, void >::transform_read
value_type * transform_read(std::string &) noexcept
Definition: H5Converter_misc.hpp:323
HighFive::details::data_converter< std::vector< std::string >, void >::transform_read
value_type * transform_read(std::vector< std::string > &)
Definition: H5Converter_misc.hpp:357
HighFive::details::data_converter
Definition: H5_definitions.hpp:57
H5Utils.hpp
HighFive
Definition: H5_definitions.hpp:15
HighFive::DataSpaceException
Exception specific to HighFive DataSpace interface.
Definition: H5Exception.hpp:99
HighFive::details::data_converter< std::vector< Reference >, void >::_vec_align
std::vector< typename type_of_array< hobj_ref_t >::type > _vec_align
Definition: H5Converter_misc.hpp:427