HighFive 2.7.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) 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#include <cstring>
13#include <numeric>
14
15#include "../H5Reference.hpp"
16#ifdef H5_USE_BOOST
17#include <boost/multi_array.hpp>
18// starting Boost 1.64, serialization header must come before ublas
19#include <boost/serialization/vector.hpp>
20#include <boost/numeric/ublas/matrix.hpp>
21#endif
22#ifdef H5_USE_EIGEN
23#include <Eigen/Eigen>
24#endif
25
26namespace HighFive {
27namespace details {
28
29inline bool checkDimensions(const std::vector<size_t>& dims, size_t n_dim_requested) {
30 size_t n_dim_actual = dims.size();
31
32 // We should allow reading scalar from shapes like `(1, 1, 1)`.
33 if (n_dim_requested == 0) {
34 if (n_dim_actual == 0ul) {
35 return true;
36 }
37
38 return size_t(std::count(dims.begin(), dims.end(), 1ul)) == n_dim_actual;
39 }
40
41 // For non-scalar datasets, we can squeeze away singleton dimension, but
42 // we never add any.
43 if (n_dim_actual < n_dim_requested) {
44 return false;
45 }
46
47 // Special case for 1-dimensional arrays, which can squeeze `1`s from either
48 // side simultaneously if needed.
49 if (n_dim_requested == 1ul) {
50 return n_dim_actual >= 1ul &&
51 size_t(std::count(dims.begin(), dims.end(), 1ul)) >= n_dim_actual - 1ul;
52 }
53
54 // All other cases strip front only. This avoid unstable behaviour when
55 // squeezing singleton dimensions.
56 size_t n_dim_excess = n_dim_actual - n_dim_requested;
57
58 bool squeeze_back = true;
59 for (size_t i = 1; i <= n_dim_excess; ++i) {
60 if (dims[n_dim_actual - i] != 1) {
61 squeeze_back = false;
62 break;
63 }
64 }
65
66 return squeeze_back;
67}
68
69
70inline std::vector<size_t> squeezeDimensions(const std::vector<size_t>& dims,
71 size_t n_dim_requested) {
72 auto format_error_message = [&]() -> std::string {
73 return "Can't interpret dims = " + format_vector(dims) + " as " +
74 std::to_string(n_dim_requested) + "-dimensional.";
75 };
76
77 if (n_dim_requested == 0) {
78 if (!checkDimensions(dims, n_dim_requested)) {
79 throw std::invalid_argument(format_error_message());
80 }
81
82 return {1ul};
83 }
84
85 auto n_dim = dims.size();
86 if (n_dim < n_dim_requested) {
87 throw std::invalid_argument(format_error_message());
88 }
89
90 if (n_dim_requested == 1ul) {
91 size_t non_singleton_dim = size_t(-1);
92 for (size_t i = 0; i < n_dim; ++i) {
93 if (dims[i] != 1ul) {
94 if (non_singleton_dim == size_t(-1)) {
95 non_singleton_dim = i;
96 } else {
97 throw std::invalid_argument(format_error_message());
98 }
99 }
100 }
101
102 return {dims[std::min(non_singleton_dim, n_dim - 1)]};
103 }
104
105 size_t n_dim_excess = dims.size() - n_dim_requested;
106 for (size_t i = 1; i <= n_dim_excess; ++i) {
107 if (dims[n_dim - i] != 1) {
108 throw std::invalid_argument(format_error_message());
109 }
110 }
111
112 return std::vector<size_t>(dims.begin(),
113 dims.end() - static_cast<std::ptrdiff_t>(n_dim_excess));
114}
115} // namespace details
116
117
118inline size_t compute_total_size(const std::vector<size_t>& dims) {
119 return std::accumulate(dims.begin(), dims.end(), size_t{1u}, std::multiplies<size_t>());
120}
121
122template <typename T>
123using unqualified_t = typename std::remove_const<typename std::remove_reference<T>::type>::type;
124
125/*****
126inspector<T> {
127 using type = T
128 // base_type is the base type inside c++ (e.g. std::vector<int> => int)
129 using base_type
130 // hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector<std::string> => const char*)
131 using hdf5_type
132
133 // Number of dimensions starting from here
134 static constexpr size_t recursive_ndim
135 // Is the inner type trivially copyable for optimisation
136 // If this value is true: data() is mandatory
137 // If this value is false: getSizeVal, getSize, serialize, unserialize are mandatory
138 static constexpr bool is_trivially_copyable
139
140 // Reading:
141 // Allocate the value following dims (should be recursive)
142 static void prepare(type& val, const std::vector<std::size_t> dims)
143 // Return the size of the vector pass to/from hdf5 from a vector of dims
144 static size_t getSize(const std::vector<size_t>& dims)
145 // Return a pointer of the first value of val (for reading)
146 static hdf5_type* data(type& val)
147 // Take a serialized vector 'in', some dims and copy value to val (for reading)
148 static void unserialize(const hdf5_type* in, const std::vector<size_t>&i, type& val)
149
150
151 // Writing:
152 // Return the size of the vector pass to/from hdf5 from a value
153 static size_t getSizeVal(const type& val)
154 // Return a point of the first value of val
155 static const hdf5_type* data(const type& val)
156 // Take a val and serialize it inside 'out'
157 static void serialize(const type& val, hdf5_type* out)
158 // Return an array of dimensions of the space needed for writing val
159 static std::vector<size_t> getDimensions(const type& val)
160}
161*****/
162
163
164namespace details {
165template <typename T>
166struct type_helper {
167 using type = unqualified_t<T>;
168 using base_type = unqualified_t<T>;
169 using hdf5_type = base_type;
170
171 static constexpr size_t ndim = 0;
172 static constexpr size_t recursive_ndim = ndim;
173 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
174
175 static std::vector<size_t> getDimensions(const type& /* val */) {
176 return {};
177 }
178
179 static size_t getSizeVal(const type& val) {
180 return compute_total_size(getDimensions(val));
181 }
182
183 static size_t getSize(const std::vector<size_t>& dims) {
184 return compute_total_size(dims);
185 }
186
187 static void prepare(type& /* val */, const std::vector<size_t>& /* dims */) {}
188
189 static hdf5_type* data(type& val) {
190 static_assert(is_trivially_copyable, "The type is not trivially copyable");
191 return &val;
192 }
193
194 static const hdf5_type* data(const type& val) {
195 static_assert(is_trivially_copyable, "The type is not trivially copyable");
196 return &val;
197 }
198
199 static void serialize(const type& val, hdf5_type* m) {
200 static_assert(is_trivially_copyable, "The type is not trivially copyable");
201 *m = val;
202 }
203
204 static void unserialize(const hdf5_type* vec,
205 const std::vector<size_t>& /* dims */,
206 type& val) {
207 static_assert(is_trivially_copyable, "The type is not trivially copyable");
208 val = vec[0];
209 }
210};
211
212template <typename T>
213struct inspector: type_helper<T> {};
214
215enum class Boolean : int8_t {
216 HighFiveFalse = 0,
217 HighFiveTrue = 1,
218};
219
220template <>
221struct inspector<bool>: type_helper<bool> {
222 using base_type = Boolean;
223 using hdf5_type = int8_t;
224
225 static constexpr bool is_trivially_copyable = false;
226
227 static hdf5_type* data(type& /* val */) {
228 throw DataSpaceException("A boolean cannot be read directly.");
229 }
230
231 static const hdf5_type* data(const type& /* val */) {
232 throw DataSpaceException("A boolean cannot be written directly.");
233 }
234
235 static void unserialize(const hdf5_type* vec,
236 const std::vector<size_t>& /* dims */,
237 type& val) {
238 val = vec[0] != 0 ? true : false;
239 }
240
241 static void serialize(const type& val, hdf5_type* m) {
242 *m = val ? 1 : 0;
243 }
244};
245
246template <>
247struct inspector<std::string>: type_helper<std::string> {
248 using hdf5_type = const char*;
249
250 static hdf5_type* data(type& /* val */) {
251 throw DataSpaceException("A std::string cannot be read directly.");
252 }
253
254 static const hdf5_type* data(const type& /* val */) {
255 throw DataSpaceException("A std::string cannot be written directly.");
256 }
257
258 static void serialize(const type& val, hdf5_type* m) {
259 *m = val.c_str();
260 }
261
262 static void unserialize(const hdf5_type* vec,
263 const std::vector<size_t>& /* dims */,
264 type& val) {
265 val = vec[0];
266 }
267};
268
269template <>
270struct inspector<Reference>: type_helper<Reference> {
271 using hdf5_type = hobj_ref_t;
272
273 static constexpr bool is_trivially_copyable = false;
274
275 static hdf5_type* data(type& /* val */) {
276 throw DataSpaceException("A Reference cannot be read directly.");
277 }
278
279 static const hdf5_type* data(const type& /* val */) {
280 throw DataSpaceException("A Reference cannot be written directly.");
281 }
282
283 static void serialize(const type& val, hdf5_type* m) {
284 hobj_ref_t ref;
285 val.create_ref(&ref);
286 *m = ref;
287 }
288
289 static void unserialize(const hdf5_type* vec,
290 const std::vector<size_t>& /* dims */,
291 type& val) {
292 val = type{vec[0]};
293 }
294};
295
296template <size_t N>
297struct inspector<FixedLenStringArray<N>> {
298 using type = FixedLenStringArray<N>;
299 using value_type = char*;
300 using base_type = FixedLenStringArray<N>;
301 using hdf5_type = char;
302
303 static constexpr size_t ndim = 1;
304 static constexpr size_t recursive_ndim = ndim;
305 static constexpr bool is_trivially_copyable = false;
306
307 static std::vector<size_t> getDimensions(const type& val) {
308 return std::vector<size_t>{val.size()};
309 }
310
311 static size_t getSizeVal(const type& val) {
312 return N * compute_total_size(getDimensions(val));
313 }
314
315 static size_t getSize(const std::vector<size_t>& dims) {
316 return N * compute_total_size(dims);
317 }
318
319 static void prepare(type& /* val */, const std::vector<size_t>& dims) {
320 if (dims[0] > N) {
321 std::ostringstream os;
322 os << "Size of FixedlenStringArray (" << N << ") is too small for dims (" << dims[0]
323 << ").";
324 throw DataSpaceException(os.str());
325 }
326 }
327
328 static hdf5_type* data(type& val) {
329 return val.data();
330 }
331
332 static const hdf5_type* data(const type& val) {
333 return val.data();
334 }
335
336 static void serialize(const type& val, hdf5_type* m) {
337 for (size_t i = 0; i < val.size(); ++i) {
338 std::memcpy(m + i * N, val[i], N);
339 }
340 }
341
342 static void unserialize(const hdf5_type* vec, const std::vector<size_t>& dims, type& val) {
343 for (size_t i = 0; i < dims[0]; ++i) {
344 std::array<char, N> s;
345 std::memcpy(s.data(), vec + (i * N), N);
346 val.push_back(s);
347 }
348 }
349};
350
351template <typename T>
352struct inspector<std::vector<T>> {
353 using type = std::vector<T>;
354 using value_type = unqualified_t<T>;
355 using base_type = typename inspector<value_type>::base_type;
356 using hdf5_type = typename inspector<value_type>::hdf5_type;
357
358 static constexpr size_t ndim = 1;
359 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
360 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
361 inspector<value_type>::is_trivially_copyable;
362
363 static std::vector<size_t> getDimensions(const type& val) {
364 std::vector<size_t> sizes(recursive_ndim, 1ul);
365 sizes[0] = val.size();
366 if (!val.empty()) {
367 auto s = inspector<value_type>::getDimensions(val[0]);
368 std::copy(s.begin(), s.end(), sizes.begin() + 1);
369 }
370 return sizes;
371 }
372
373 static size_t getSizeVal(const type& val) {
374 return compute_total_size(getDimensions(val));
375 }
376
377 static size_t getSize(const std::vector<size_t>& dims) {
378 return compute_total_size(dims);
379 }
380
381 static void prepare(type& val, const std::vector<size_t>& dims) {
382 val.resize(dims[0]);
383 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
384 for (auto&& e: val) {
385 inspector<value_type>::prepare(e, next_dims);
386 }
387 }
388
389 static hdf5_type* data(type& val) {
390 return inspector<value_type>::data(val[0]);
391 }
392
393 static const hdf5_type* data(const type& val) {
394 return inspector<value_type>::data(val[0]);
395 }
396
397 static void serialize(const type& val, hdf5_type* m) {
398 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
399 for (auto&& e: val) {
400 inspector<value_type>::serialize(e, m);
401 m += subsize;
402 }
403 }
404
405 static void unserialize(const hdf5_type* vec_align,
406 const std::vector<size_t>& dims,
407 type& val) {
408 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
409 size_t next_size = compute_total_size(next_dims);
410 for (size_t i = 0; i < dims[0]; ++i) {
411 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
412 }
413 }
414};
415
416template <>
417struct inspector<std::vector<bool>> {
418 using type = std::vector<bool>;
419 using value_type = bool;
420 using base_type = Boolean;
421 using hdf5_type = uint8_t;
422
423 static constexpr size_t ndim = 1;
424 static constexpr size_t recursive_ndim = ndim;
425 static constexpr bool is_trivially_copyable = false;
426
427 static std::vector<size_t> getDimensions(const type& val) {
428 std::vector<size_t> sizes{val.size()};
429 return sizes;
430 }
431
432 static size_t getSizeVal(const type& val) {
433 return val.size();
434 }
435
436 static size_t getSize(const std::vector<size_t>& dims) {
437 if (dims.size() > 1) {
438 throw DataSpaceException("std::vector<bool> is only 1 dimension.");
439 }
440 return dims[0];
441 }
442
443 static void prepare(type& val, const std::vector<size_t>& dims) {
444 if (dims.size() > 1) {
445 throw DataSpaceException("std::vector<bool> is only 1 dimension.");
446 }
447 val.resize(dims[0]);
448 }
449
450 static hdf5_type* data(type& /* val */) {
451 throw DataSpaceException("A std::vector<bool> cannot be read directly.");
452 }
453
454 static const hdf5_type* data(const type& /* val */) {
455 throw DataSpaceException("A std::vector<bool> cannot be written directly.");
456 }
457
458 static void serialize(const type& val, hdf5_type* m) {
459 for (size_t i = 0; i < val.size(); ++i) {
460 m[i] = val[i] ? 1 : 0;
461 }
462 }
463
464 static void unserialize(const hdf5_type* vec_align,
465 const std::vector<size_t>& dims,
466 type& val) {
467 for (size_t i = 0; i < dims[0]; ++i) {
468 val[i] = vec_align[i] != 0 ? true : false;
469 }
470 }
471};
472
473template <typename T, size_t N>
474struct inspector<std::array<T, N>> {
475 using type = std::array<T, N>;
476 using value_type = unqualified_t<T>;
477 using base_type = typename inspector<value_type>::base_type;
478 using hdf5_type = typename inspector<value_type>::hdf5_type;
479
480 static constexpr size_t ndim = 1;
481 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
482 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
483 inspector<value_type>::is_trivially_copyable;
484
485 static std::vector<size_t> getDimensions(const type& val) {
486 std::vector<size_t> sizes{N};
487 if (!val.empty()) {
488 auto s = inspector<value_type>::getDimensions(val[0]);
489 sizes.insert(sizes.end(), s.begin(), s.end());
490 }
491 return sizes;
492 }
493
494 static size_t getSizeVal(const type& val) {
495 return compute_total_size(getDimensions(val));
496 }
497
498 static size_t getSize(const std::vector<size_t>& dims) {
499 return compute_total_size(dims);
500 }
501
502 static void prepare(type& /* val */, const std::vector<size_t>& dims) {
503 if (dims[0] > N) {
504 std::ostringstream os;
505 os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ").";
506 throw DataSpaceException(os.str());
507 }
508 }
509
510 static hdf5_type* data(type& val) {
511 return inspector<value_type>::data(val[0]);
512 }
513
514 static const hdf5_type* data(const type& val) {
515 return inspector<value_type>::data(val[0]);
516 }
517
518 static void serialize(const type& val, hdf5_type* m) {
519 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
520 for (auto& e: val) {
521 inspector<value_type>::serialize(e, m);
522 m += subsize;
523 }
524 }
525
526 static void unserialize(const hdf5_type* vec_align,
527 const std::vector<size_t>& dims,
528 type& val) {
529 if (dims[0] != N) {
530 std::ostringstream os;
531 os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with "
532 << N << " elements.";
533 throw DataSpaceException(os.str());
534 }
535 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
536 size_t next_size = compute_total_size(next_dims);
537 for (size_t i = 0; i < dims[0]; ++i) {
538 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
539 }
540 }
541};
542
543// Cannot be use for reading
544template <typename T>
545struct inspector<T*> {
546 using type = T*;
547 using value_type = unqualified_t<T>;
548 using base_type = typename inspector<value_type>::base_type;
549 using hdf5_type = typename inspector<value_type>::hdf5_type;
550
551 static constexpr size_t ndim = 1;
552 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
553 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
554 inspector<value_type>::is_trivially_copyable;
555
556 static size_t getSizeVal(const type& /* val */) {
557 throw DataSpaceException("Not possible to have size of a T*");
558 }
559
560 static std::vector<size_t> getDimensions(const type& /* val */) {
561 throw DataSpaceException("Not possible to have size of a T*");
562 }
563
564 static const hdf5_type* data(const type& val) {
565 return reinterpret_cast<const hdf5_type*>(val);
566 }
567
568 /* it works because there is only T[][][] currently
569 we will fix it one day */
570 static void serialize(const type& /* val */, hdf5_type* /* m */) {
571 throw DataSpaceException("Not possible to serialize a T*");
572 }
573};
574
575// Cannot be use for reading
576template <typename T, size_t N>
577struct inspector<T[N]> {
578 using type = T[N];
579 using value_type = unqualified_t<T>;
580 using base_type = typename inspector<value_type>::base_type;
581 using hdf5_type = typename inspector<value_type>::hdf5_type;
582
583 static constexpr size_t ndim = 1;
584 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
585 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
586 inspector<value_type>::is_trivially_copyable;
587
588 static size_t getSizeVal(const type& val) {
589 return compute_total_size(getDimensions(val));
590 }
591
592 static std::vector<size_t> getDimensions(const type& val) {
593 std::vector<size_t> sizes{N};
594 if (N > 0) {
595 auto s = inspector<value_type>::getDimensions(val[0]);
596 sizes.insert(sizes.end(), s.begin(), s.end());
597 }
598 return sizes;
599 }
600
601 static const hdf5_type* data(const type& val) {
602 return inspector<value_type>::data(val[0]);
603 }
604
605 /* it works because there is only T[][][] currently
606 we will fix it one day */
607 static void serialize(const type& val, hdf5_type* m) {
608 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
609 for (size_t i = 0; i < N; ++i) {
610 inspector<value_type>::serialize(val[i], m + i * subsize);
611 }
612 }
613};
614
615#ifdef H5_USE_EIGEN
616template <typename T, int M, int N>
617struct inspector<Eigen::Matrix<T, M, N>> {
618 using type = Eigen::Matrix<T, M, N>;
619 using value_type = T;
620 using base_type = typename inspector<value_type>::base_type;
621 using hdf5_type = base_type;
622
623 static constexpr size_t ndim = 2;
624 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
625 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
626 inspector<value_type>::is_trivially_copyable;
627
628 static std::vector<size_t> getDimensions(const type& val) {
629 std::vector<size_t> sizes{static_cast<size_t>(val.rows()), static_cast<size_t>(val.cols())};
630 auto s = inspector<value_type>::getDimensions(val.data()[0]);
631 sizes.insert(sizes.end(), s.begin(), s.end());
632 return sizes;
633 }
634
635 static size_t getSizeVal(const type& val) {
636 return compute_total_size(getDimensions(val));
637 }
638
639 static size_t getSize(const std::vector<size_t>& dims) {
640 return compute_total_size(dims);
641 }
642
643 static void prepare(type& val, const std::vector<size_t>& dims) {
644 if (dims[0] != static_cast<size_t>(val.rows()) ||
645 dims[1] != static_cast<size_t>(val.cols())) {
646 val.resize(static_cast<typename type::Index>(dims[0]),
647 static_cast<typename type::Index>(dims[1]));
648 }
649 }
650
651 static hdf5_type* data(type& val) {
652 return inspector<value_type>::data(*val.data());
653 }
654
655 static const hdf5_type* data(const type& val) {
656 return inspector<value_type>::data(*val.data());
657 }
658
659 static void serialize(const type& val, hdf5_type* m) {
660 std::memcpy(m, val.data(), static_cast<size_t>(val.size()) * sizeof(hdf5_type));
661 }
662
663 static void unserialize(const hdf5_type* vec_align,
664 const std::vector<size_t>& dims,
665 type& val) {
666 if (dims.size() < 2) {
667 std::ostringstream os;
668 os << "Impossible to pair DataSet with " << dims.size()
669 << " dimensions into an eigen-matrix.";
670 throw DataSpaceException(os.str());
671 }
672 std::memcpy(val.data(), vec_align, compute_total_size(dims) * sizeof(hdf5_type));
673 }
674};
675#endif
676
677#ifdef H5_USE_BOOST
678template <typename T, size_t Dims>
679struct inspector<boost::multi_array<T, Dims>> {
680 using type = boost::multi_array<T, Dims>;
681 using value_type = T;
682 using base_type = typename inspector<value_type>::base_type;
683 using hdf5_type = typename inspector<value_type>::hdf5_type;
684
685 static constexpr size_t ndim = Dims;
686 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
687 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
688 inspector<value_type>::is_trivially_copyable;
689
690 static std::vector<size_t> getDimensions(const type& val) {
691 std::vector<size_t> sizes;
692 for (size_t i = 0; i < ndim; ++i) {
693 sizes.push_back(val.shape()[i]);
694 }
695 auto s = inspector<value_type>::getDimensions(val.data()[0]);
696 sizes.insert(sizes.end(), s.begin(), s.end());
697 return sizes;
698 }
699
700 static size_t getSizeVal(const type& val) {
701 return compute_total_size(getDimensions(val));
702 }
703
704 static size_t getSize(const std::vector<size_t>& dims) {
705 return compute_total_size(dims);
706 }
707
708 static void prepare(type& val, const std::vector<size_t>& dims) {
709 if (dims.size() < ndim) {
710 std::ostringstream os;
711 os << "Only '" << dims.size() << "' given but boost::multi_array is of size '" << ndim
712 << "'.";
713 throw DataSpaceException(os.str());
714 }
715 boost::array<typename type::index, Dims> ext;
716 std::copy(dims.begin(), dims.begin() + ndim, ext.begin());
717 val.resize(ext);
718 std::vector<size_t> next_dims(dims.begin() + Dims, dims.end());
719 std::size_t size = std::accumulate(dims.begin(),
720 dims.begin() + Dims,
721 std::size_t{1},
722 std::multiplies<size_t>());
723 for (size_t i = 0; i < size; ++i) {
724 inspector<value_type>::prepare(*(val.origin() + i), next_dims);
725 }
726 }
727
728 static hdf5_type* data(type& val) {
729 return inspector<value_type>::data(*val.data());
730 }
731
732 static const hdf5_type* data(const type& val) {
733 return inspector<value_type>::data(*val.data());
734 }
735
736 static void serialize(const type& val, hdf5_type* m) {
737 size_t size = val.num_elements();
738 size_t subsize = inspector<value_type>::getSizeVal(*val.origin());
739 for (size_t i = 0; i < size; ++i) {
740 inspector<value_type>::serialize(*(val.origin() + i), m + i * subsize);
741 }
742 }
743
744 static void unserialize(const hdf5_type* vec_align,
745 const std::vector<size_t>& dims,
746 type& val) {
747 std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
748 size_t subsize = compute_total_size(next_dims);
749 for (size_t i = 0; i < val.num_elements(); ++i) {
750 inspector<value_type>::unserialize(vec_align + i * subsize,
751 next_dims,
752 *(val.origin() + i));
753 }
754 }
755};
756
757template <typename T>
758struct inspector<boost::numeric::ublas::matrix<T>> {
759 using type = boost::numeric::ublas::matrix<T>;
760 using value_type = unqualified_t<T>;
761 using base_type = typename inspector<value_type>::base_type;
762 using hdf5_type = typename inspector<value_type>::hdf5_type;
763
764 static constexpr size_t ndim = 2;
765 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
766 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
767 inspector<value_type>::is_trivially_copyable;
768
769 static std::vector<size_t> getDimensions(const type& val) {
770 std::vector<size_t> sizes{val.size1(), val.size2()};
771 auto s = inspector<value_type>::getDimensions(val(0, 0));
772 sizes.insert(sizes.end(), s.begin(), s.end());
773 return sizes;
774 }
775
776 static size_t getSizeVal(const type& val) {
777 return compute_total_size(getDimensions(val));
778 }
779
780 static size_t getSize(const std::vector<size_t>& dims) {
781 return compute_total_size(dims);
782 }
783
784 static void prepare(type& val, const std::vector<size_t>& dims) {
785 if (dims.size() < ndim) {
786 std::ostringstream os;
787 os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim
788 << " boost::numeric::ublas::matrix";
789 throw DataSpaceException(os.str());
790 }
791 val.resize(dims[0], dims[1], false);
792 }
793
794 static hdf5_type* data(type& val) {
795 return inspector<value_type>::data(val(0, 0));
796 }
797
798 static const hdf5_type* data(const type& val) {
799 return inspector<value_type>::data(val(0, 0));
800 }
801
802 static void serialize(const type& val, hdf5_type* m) {
803 size_t size = val.size1() * val.size2();
804 size_t subsize = inspector<value_type>::getSizeVal(val(0, 0));
805 for (size_t i = 0; i < size; ++i) {
806 inspector<value_type>::serialize(*(&val(0, 0) + i), m + i * subsize);
807 }
808 }
809
810 static void unserialize(const hdf5_type* vec_align,
811 const std::vector<size_t>& dims,
812 type& val) {
813 std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
814 size_t subsize = compute_total_size(next_dims);
815 size_t size = val.size1() * val.size2();
816 for (size_t i = 0; i < size; ++i) {
817 inspector<value_type>::unserialize(vec_align + i * subsize,
818 next_dims,
819 *(&val(0, 0) + i));
820 }
821 }
822};
823#endif
824
825template <typename T>
826struct Writer {
827 using hdf5_type = typename inspector<T>::hdf5_type;
828 const hdf5_type* get_pointer() {
829 if (vec.empty()) {
830 return ptr;
831 } else {
832 return vec.data();
833 }
834 }
835 std::vector<hdf5_type> vec{};
836 const hdf5_type* ptr{nullptr};
837};
838
839template <typename T>
840struct Reader {
841 using type = unqualified_t<T>;
842 using hdf5_type = typename inspector<type>::hdf5_type;
843
844 Reader(const std::vector<size_t>& _dims, type& _val)
845 : dims(_dims)
846 , val(_val) {}
847
848 hdf5_type* get_pointer() {
849 if (vec.empty()) {
850 return inspector<type>::data(val);
851 } else {
852 return vec.data();
853 }
854 }
855
856 void unserialize() {
857 if (!vec.empty()) {
858 inspector<type>::unserialize(vec.data(), dims, val);
859 }
860 }
861
862 std::vector<size_t> dims{};
863 std::vector<hdf5_type> vec{};
864 type& val{};
865};
866
867struct data_converter {
868 template <typename T>
869 static typename std::enable_if<inspector<T>::is_trivially_copyable, Writer<T>>::type serialize(
870 const typename inspector<T>::type& val) {
871 Writer<T> w;
872 w.ptr = inspector<T>::data(val);
873 return w;
874 }
875
876 template <typename T>
877 static typename std::enable_if<!inspector<T>::is_trivially_copyable, Writer<T>>::type serialize(
878 const typename inspector<T>::type& val) {
879 Writer<T> w;
880 w.vec.resize(inspector<T>::getSizeVal(val));
881 inspector<T>::serialize(val, w.vec.data());
882 return w;
883 }
884
885 template <typename T>
886 static
887 typename std::enable_if<inspector<unqualified_t<T>>::is_trivially_copyable, Reader<T>>::type
888 get_reader(const std::vector<size_t>& dims, T& val) {
889 auto effective_dims = details::squeezeDimensions(dims, inspector<T>::recursive_ndim);
890 Reader<T> r(effective_dims, val);
891 inspector<T>::prepare(r.val, effective_dims);
892 return r;
893 }
894
895 template <typename T>
896 static typename std::enable_if<!inspector<unqualified_t<T>>::is_trivially_copyable,
897 Reader<T>>::type
898 get_reader(const std::vector<size_t>& dims, T& val) {
899 auto effective_dims = details::squeezeDimensions(dims, inspector<T>::recursive_ndim);
900
901 Reader<T> r(effective_dims, val);
902 inspector<T>::prepare(r.val, effective_dims);
903 r.vec.resize(inspector<T>::getSize(effective_dims));
904 return r;
905 }
906};
907
908} // namespace details
909} // namespace HighFive
Exception specific to HighFive DataSpace interface.
Definition H5Exception.hpp:112
A structure representing a set of fixed-length strings.
Definition H5DataType.hpp:284
std::size_t size() const noexcept
Definition H5DataType.hpp:326
An HDF5 (object) reference type.
Definition H5Reference.hpp:33
Definition H5_definitions.hpp:15
typename std::remove_const< typename std::remove_reference< T >::type >::type unqualified_t
Definition H5Converter_misc.hpp:123
size_t compute_total_size(const std::vector< size_t > &dims)
Definition H5Converter_misc.hpp:118