HighFive 3.2.0
HighFive - Header-only C++ HDF5 interface
Loading...
Searching...
No Matches
mdspan.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "H5Exception.hpp"
5
6#include <mdspan>
7#include <vector>
8#include <array>
9#include <sstream>
10#include <utility>
11#include <type_traits>
12
13namespace HighFive {
14namespace details {
15
16// Specialization for std::mdspan
17template <class ElementType, class Extents, class LayoutPolicy, class AccessorPolicy>
18struct inspector<std::mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>> {
19 using type = std::mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>;
20 using value_type = typename type::element_type;
21 using base_type = typename inspector<value_type>::base_type;
22 using hdf5_type = base_type;
23 using extents_type = typename type::extents_type;
24 using accessor_type = typename type::accessor_type;
25
26 static constexpr size_t ndim = type::rank();
27 static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
28 static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
29
30 static constexpr bool is_trivially_copyable =
31 std::is_trivially_copyable<value_type>::value &&
32 inspector<value_type>::is_trivially_nestable &&
33 (std::is_same_v<std::default_accessor<value_type>, accessor_type>
34#ifdef __cpp_lib_aligned_accessor
35 || std::is_same_v<std::aligned_accessor<value_type>, accessor_type>
36#endif
37 ) &&
38 (std::is_same_v<typename type::layout_type, std::layout_right> ||
39 (std::is_same_v<typename type::layout_type, std::layout_left> && ndim == 1));
40 static constexpr bool is_trivially_nestable = false;
41
42 private:
43 using index_type = typename extents_type::index_type;
44
45 // Helper to access the first element (at index 0 in all dimensions)
46 static auto get_first_element(const type& val) {
47 std::array<index_type, ndim> indices{};
48 return val[indices];
49 }
50
51 template <typename T>
52 static auto data_impl(T& val) -> decltype(inspector<value_type>::data(*val.data_handle())) {
53 if (!is_trivially_copyable) {
54 throw DataSetException("Invalid use of `inspector<std::mdspan<...>>::data`.");
55 }
56
57 if (val.empty()) {
58 return nullptr;
59 }
60
61 return inspector<value_type>::data(*val.data_handle());
62 }
63
64 public:
65 static size_t getRank(const type& val) {
66 if (val.empty()) {
67 return min_ndim;
68 }
69 return ndim + inspector<value_type>::getRank(get_first_element(val));
70 }
71
72 static std::vector<size_t> getDimensions(const type& val) {
73 std::vector<size_t> sizes;
74 sizes.reserve(ndim);
75 for (size_t r = 0; r < ndim; ++r) {
76 sizes.push_back(val.extent(r));
77 }
78 if (!val.empty()) {
79 auto s = inspector<value_type>::getDimensions(get_first_element(val));
80 sizes.insert(sizes.end(), s.begin(), s.end());
81 }
82 return sizes;
83 }
84
85 static void prepare(type& val, const std::vector<size_t>& dims) {
86 if (dims.size() < ndim) {
87 std::ostringstream os;
88 os << "Impossible to pair DataSet with " << dims.size()
89 << " dimensions into an mdspan with rank " << ndim << ".";
90 throw DataSpaceException(os.str());
91 }
92
93 // Check that dimensions match
94 for (size_t r = 0; r < ndim; ++r) {
95 if (dims[r] != val.extent(r)) {
96 std::ostringstream os;
97 os << "Mismatching dimensions for mdspan: expected " << val.extent(r)
98 << " for dimension " << r << ", but got " << dims[r] << ".";
99 throw DataSpaceException(os.str());
100 }
101 }
102 }
103
104 static hdf5_type* data(type& val) {
105 return data_impl(val);
106 }
107
108 static const hdf5_type* data(const type& val) {
109 return data_impl(val);
110 }
111
112 static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
113 auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
114 auto subsize = compute_total_size(subdims);
115
116 std::array<index_type, ndim> indices{};
117 auto iterate = [&](auto& self, size_t dim) -> void {
118 if (dim == ndim) {
119 // Base case: serialize element
120 inspector<value_type>::serialize(val[indices], subdims, m);
121 m += subsize;
122 } else {
123 // Recursive case: iterate over current dimension
124 const auto n = static_cast<index_type>(val.extent(dim));
125 for (indices[dim] = 0; indices[dim] < n; ++indices[dim]) {
126 self(self, dim + 1);
127 }
128 }
129 };
130
131 iterate(iterate, 0);
132 }
133
134 static void unserialize(const hdf5_type* vec_align,
135 const std::vector<size_t>& dims,
136 type& val) {
137 if (dims.size() < ndim) {
138 std::ostringstream os;
139 os << "Impossible to pair DataSet with " << dims.size()
140 << " dimensions into an mdspan with rank " << ndim << ".";
141 throw DataSpaceException(os.str());
142 }
143
144 auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
145 auto subsize = compute_total_size(subdims);
146
147 std::array<index_type, ndim> indices{};
148 auto iterate = [&](auto& self, size_t dim) -> void {
149 if (dim == ndim) {
150 // Base case: unserialize element
151 inspector<value_type>::unserialize(vec_align, subdims, val[indices]);
152 vec_align += subsize;
153 } else {
154 // Recursive case: iterate over current dimension
155 const auto n = static_cast<index_type>(dims[dim]);
156 for (indices[dim] = 0; indices[dim] < n; ++indices[dim]) {
157 self(self, dim + 1);
158 }
159 }
160 };
161
162 iterate(iterate, 0);
163 }
164};
165
166} // namespace details
167} // namespace HighFive
Definition assert_compatible_spaces.hpp:15
size_t compute_total_size(const std::vector< size_t > &dims)
Definition compute_total_size.hpp:10