15#include "../H5Reference.hpp"
17#include <boost/multi_array.hpp>
19#include <boost/serialization/vector.hpp>
20#include <boost/numeric/ublas/matrix.hpp>
29inline bool checkDimensions(
const std::vector<size_t>& dims,
size_t n_dim_requested) {
30 size_t n_dim_actual = dims.size();
33 if (n_dim_requested == 0) {
34 if (n_dim_actual == 0ul) {
38 return size_t(std::count(dims.begin(), dims.end(), 1ul)) == n_dim_actual;
43 if (n_dim_actual < n_dim_requested) {
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;
56 size_t n_dim_excess = n_dim_actual - n_dim_requested;
58 bool squeeze_back =
true;
59 for (
size_t i = 1; i <= n_dim_excess; ++i) {
60 if (dims[n_dim_actual - i] != 1) {
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.";
77 if (n_dim_requested == 0) {
78 if (!checkDimensions(dims, n_dim_requested)) {
79 throw std::invalid_argument(format_error_message());
85 auto n_dim = dims.size();
86 if (n_dim < n_dim_requested) {
87 throw std::invalid_argument(format_error_message());
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) {
94 if (non_singleton_dim ==
size_t(-1)) {
95 non_singleton_dim = i;
97 throw std::invalid_argument(format_error_message());
102 return {dims[std::min(non_singleton_dim, n_dim - 1)]};
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());
112 return std::vector<size_t>(dims.begin(),
113 dims.end() -
static_cast<std::ptrdiff_t
>(n_dim_excess));
119 return std::accumulate(dims.begin(), dims.end(),
size_t{1u}, std::multiplies<size_t>());
123using unqualified_t =
typename std::remove_const<typename std::remove_reference<T>::type>::type;
169 using hdf5_type = base_type;
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;
175 static std::vector<size_t> getDimensions(
const type& ) {
179 static size_t getSizeVal(
const type& val) {
183 static size_t getSize(
const std::vector<size_t>& dims) {
187 static void prepare(type& ,
const std::vector<size_t>& ) {}
189 static hdf5_type* data(type& val) {
190 static_assert(is_trivially_copyable,
"The type is not trivially copyable");
194 static const hdf5_type* data(
const type& val) {
195 static_assert(is_trivially_copyable,
"The type is not trivially copyable");
199 static void serialize(
const type& val, hdf5_type* m) {
200 static_assert(is_trivially_copyable,
"The type is not trivially copyable");
204 static void unserialize(
const hdf5_type* vec,
205 const std::vector<size_t>& ,
207 static_assert(is_trivially_copyable,
"The type is not trivially copyable");
213struct inspector: type_helper<T> {};
215enum class Boolean : int8_t {
221struct inspector<bool>: type_helper<bool> {
222 using base_type = Boolean;
223 using hdf5_type = int8_t;
225 static constexpr bool is_trivially_copyable =
false;
227 static hdf5_type* data(type& ) {
231 static const hdf5_type* data(
const type& ) {
235 static void unserialize(
const hdf5_type* vec,
236 const std::vector<size_t>& ,
238 val = vec[0] != 0 ? true :
false;
241 static void serialize(
const type& val, hdf5_type* m) {
247struct inspector<std::string>: type_helper<std::string> {
248 using hdf5_type =
const char*;
250 static hdf5_type* data(type& ) {
254 static const hdf5_type* data(
const type& ) {
258 static void serialize(
const type& val, hdf5_type* m) {
262 static void unserialize(
const hdf5_type* vec,
263 const std::vector<size_t>& ,
270struct inspector<
Reference>: type_helper<Reference> {
271 using hdf5_type = hobj_ref_t;
273 static constexpr bool is_trivially_copyable =
false;
275 static hdf5_type* data(type& ) {
279 static const hdf5_type* data(
const type& ) {
283 static void serialize(
const type& val, hdf5_type* m) {
285 val.create_ref(&ref);
289 static void unserialize(
const hdf5_type* vec,
290 const std::vector<size_t>& ,
299 using value_type =
char*;
301 using hdf5_type = char;
303 static constexpr size_t ndim = 1;
304 static constexpr size_t recursive_ndim = ndim;
305 static constexpr bool is_trivially_copyable =
false;
307 static std::vector<size_t> getDimensions(
const type& val) {
308 return std::vector<size_t>{val.
size()};
311 static size_t getSizeVal(
const type& val) {
315 static size_t getSize(
const std::vector<size_t>& dims) {
319 static void prepare(type& ,
const std::vector<size_t>& dims) {
321 std::ostringstream os;
322 os <<
"Size of FixedlenStringArray (" << N <<
") is too small for dims (" << dims[0]
328 static hdf5_type* data(type& val) {
332 static const hdf5_type* data(
const type& val) {
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);
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);
352struct inspector<std::vector<T>> {
353 using type = std::vector<T>;
355 using base_type =
typename inspector<value_type>::base_type;
356 using hdf5_type =
typename inspector<value_type>::hdf5_type;
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;
363 static std::vector<size_t> getDimensions(
const type& val) {
364 std::vector<size_t> sizes(recursive_ndim, 1ul);
365 sizes[0] = val.size();
367 auto s = inspector<value_type>::getDimensions(val[0]);
368 std::copy(s.begin(), s.end(), sizes.begin() + 1);
373 static size_t getSizeVal(
const type& val) {
377 static size_t getSize(
const std::vector<size_t>& dims) {
381 static void prepare(type& val,
const std::vector<size_t>& dims) {
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);
389 static hdf5_type* data(type& val) {
390 return inspector<value_type>::data(val[0]);
393 static const hdf5_type* data(
const type& val) {
394 return inspector<value_type>::data(val[0]);
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);
405 static void unserialize(
const hdf5_type* vec_align,
406 const std::vector<size_t>& dims,
408 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
410 for (
size_t i = 0; i < dims[0]; ++i) {
411 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
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;
423 static constexpr size_t ndim = 1;
424 static constexpr size_t recursive_ndim = ndim;
425 static constexpr bool is_trivially_copyable =
false;
427 static std::vector<size_t> getDimensions(
const type& val) {
428 std::vector<size_t> sizes{val.size()};
432 static size_t getSizeVal(
const type& val) {
436 static size_t getSize(
const std::vector<size_t>& dims) {
437 if (dims.size() > 1) {
443 static void prepare(type& val,
const std::vector<size_t>& dims) {
444 if (dims.size() > 1) {
450 static hdf5_type* data(type& ) {
454 static const hdf5_type* data(
const type& ) {
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;
464 static void unserialize(
const hdf5_type* vec_align,
465 const std::vector<size_t>& dims,
467 for (
size_t i = 0; i < dims[0]; ++i) {
468 val[i] = vec_align[i] != 0 ? true :
false;
473template <
typename T,
size_t N>
474struct inspector<std::array<T, N>> {
475 using type = std::array<T, N>;
477 using base_type =
typename inspector<value_type>::base_type;
478 using hdf5_type =
typename inspector<value_type>::hdf5_type;
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;
485 static std::vector<size_t> getDimensions(
const type& val) {
486 std::vector<size_t> sizes{N};
488 auto s = inspector<value_type>::getDimensions(val[0]);
489 sizes.insert(sizes.end(), s.begin(), s.end());
494 static size_t getSizeVal(
const type& val) {
498 static size_t getSize(
const std::vector<size_t>& dims) {
502 static void prepare(type& ,
const std::vector<size_t>& dims) {
504 std::ostringstream os;
505 os <<
"Size of std::array (" << N <<
") is too small for dims (" << dims[0] <<
").";
510 static hdf5_type* data(type& val) {
511 return inspector<value_type>::data(val[0]);
514 static const hdf5_type* data(
const type& val) {
515 return inspector<value_type>::data(val[0]);
518 static void serialize(
const type& val, hdf5_type* m) {
519 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
521 inspector<value_type>::serialize(e, m);
526 static void unserialize(
const hdf5_type* vec_align,
527 const std::vector<size_t>& dims,
530 std::ostringstream os;
531 os <<
"Impossible to pair DataSet with " << dims[0] <<
" elements into an array with "
532 << N <<
" elements.";
535 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
537 for (
size_t i = 0; i < dims[0]; ++i) {
538 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
545struct inspector<T*> {
548 using base_type =
typename inspector<value_type>::base_type;
549 using hdf5_type =
typename inspector<value_type>::hdf5_type;
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;
556 static size_t getSizeVal(
const type& ) {
560 static std::vector<size_t> getDimensions(
const type& ) {
564 static const hdf5_type* data(
const type& val) {
565 return reinterpret_cast<const hdf5_type*
>(val);
570 static void serialize(
const type& , hdf5_type* ) {
576template <
typename T,
size_t N>
577struct inspector<T[N]> {
580 using base_type =
typename inspector<value_type>::base_type;
581 using hdf5_type =
typename inspector<value_type>::hdf5_type;
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;
588 static size_t getSizeVal(
const type& val) {
592 static std::vector<size_t> getDimensions(
const type& val) {
593 std::vector<size_t> sizes{N};
595 auto s = inspector<value_type>::getDimensions(val[0]);
596 sizes.insert(sizes.end(), s.begin(), s.end());
601 static const hdf5_type* data(
const type& val) {
602 return inspector<value_type>::data(val[0]);
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);
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;
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;
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());
635 static size_t getSizeVal(
const type& val) {
639 static size_t getSize(
const std::vector<size_t>& dims) {
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]));
651 static hdf5_type* data(type& val) {
652 return inspector<value_type>::data(*val.data());
655 static const hdf5_type* data(
const type& val) {
656 return inspector<value_type>::data(*val.data());
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));
663 static void unserialize(
const hdf5_type* vec_align,
664 const std::vector<size_t>& dims,
666 if (dims.size() < 2) {
667 std::ostringstream os;
668 os <<
"Impossible to pair DataSet with " << dims.size()
669 <<
" dimensions into an eigen-matrix.";
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;
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;
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]);
695 auto s = inspector<value_type>::getDimensions(val.data()[0]);
696 sizes.insert(sizes.end(), s.begin(), s.end());
700 static size_t getSizeVal(
const type& val) {
704 static size_t getSize(
const std::vector<size_t>& dims) {
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
715 boost::array<typename type::index, Dims> ext;
716 std::copy(dims.begin(), dims.begin() + ndim, ext.begin());
718 std::vector<size_t> next_dims(dims.begin() + Dims, dims.end());
719 std::size_t size = std::accumulate(dims.begin(),
722 std::multiplies<size_t>());
723 for (
size_t i = 0; i < size; ++i) {
724 inspector<value_type>::prepare(*(val.origin() + i), next_dims);
728 static hdf5_type* data(type& val) {
729 return inspector<value_type>::data(*val.data());
732 static const hdf5_type* data(
const type& val) {
733 return inspector<value_type>::data(*val.data());
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);
744 static void unserialize(
const hdf5_type* vec_align,
745 const std::vector<size_t>& dims,
747 std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
749 for (
size_t i = 0; i < val.num_elements(); ++i) {
750 inspector<value_type>::unserialize(vec_align + i * subsize,
752 *(val.origin() + i));
758struct inspector<boost::numeric::ublas::matrix<T>> {
759 using type = boost::numeric::ublas::matrix<T>;
761 using base_type =
typename inspector<value_type>::base_type;
762 using hdf5_type =
typename inspector<value_type>::hdf5_type;
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;
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());
776 static size_t getSizeVal(
const type& val) {
780 static size_t getSize(
const std::vector<size_t>& dims) {
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";
791 val.resize(dims[0], dims[1],
false);
794 static hdf5_type* data(type& val) {
795 return inspector<value_type>::data(val(0, 0));
798 static const hdf5_type* data(
const type& val) {
799 return inspector<value_type>::data(val(0, 0));
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);
810 static void unserialize(
const hdf5_type* vec_align,
811 const std::vector<size_t>& dims,
813 std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
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,
827 using hdf5_type =
typename inspector<T>::hdf5_type;
828 const hdf5_type* get_pointer() {
835 std::vector<hdf5_type> vec{};
836 const hdf5_type* ptr{
nullptr};
842 using hdf5_type =
typename inspector<type>::hdf5_type;
844 Reader(
const std::vector<size_t>& _dims, type& _val)
848 hdf5_type* get_pointer() {
850 return inspector<type>::data(val);
858 inspector<type>::unserialize(vec.data(), dims, val);
862 std::vector<size_t> dims{};
863 std::vector<hdf5_type> vec{};
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) {
872 w.ptr = inspector<T>::data(val);
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) {
880 w.vec.resize(inspector<T>::getSizeVal(val));
881 inspector<T>::serialize(val, w.vec.data());
885 template <
typename T>
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);
895 template <
typename T>
896 static typename std::enable_if<!inspector<unqualified_t<T>>::is_trivially_copyable,
898 get_reader(
const std::vector<size_t>& dims, T& val) {
899 auto effective_dims = details::squeezeDimensions(dims, inspector<T>::recursive_ndim);
901 Reader<T> r(effective_dims, val);
902 inspector<T>::prepare(r.val, effective_dims);
903 r.vec.resize(inspector<T>::getSize(effective_dims));
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