File indexing completed on 2026-09-20 09:14:31
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <algorithm>
0012 #include <cassert>
0013 #include <functional>
0014 #include <numeric>
0015 #include <sstream>
0016 #include <string>
0017
0018 #include "h5d_wrapper.hpp"
0019 #include "h5s_wrapper.hpp"
0020
0021 #include "H5ReadWrite_misc.hpp"
0022 #include "H5Converter_misc.hpp"
0023 #include "squeeze.hpp"
0024 #include "compute_total_size.hpp"
0025 #include "assert_compatible_spaces.hpp"
0026
0027 namespace HighFive {
0028
0029 namespace details {
0030
0031
0032
0033
0034 inline const DataSet& get_dataset(const Selection& sel) {
0035 return sel.getDataset();
0036 }
0037
0038 inline const DataSet& get_dataset(const DataSet& ds) {
0039 return ds;
0040 }
0041
0042
0043
0044
0045 inline hid_t get_memspace_id(const Selection& ptr) {
0046 return ptr.getMemSpace().getId();
0047 }
0048
0049 inline hid_t get_memspace_id(const DataSet&) {
0050 return H5S_ALL;
0051 }
0052 }
0053
0054 inline ElementSet::ElementSet(std::initializer_list<std::size_t> list)
0055 : _ids(list) {}
0056
0057 inline ElementSet::ElementSet(std::initializer_list<std::vector<std::size_t>> list)
0058 : ElementSet(std::vector<std::vector<std::size_t>>(list)) {}
0059
0060 inline ElementSet::ElementSet(const std::vector<std::size_t>& element_ids)
0061 : _ids(element_ids) {}
0062
0063 inline ElementSet::ElementSet(const std::vector<std::vector<std::size_t>>& element_ids) {
0064 for (const auto& vec: element_ids) {
0065 std::copy(vec.begin(), vec.end(), std::back_inserter(_ids));
0066 }
0067 }
0068
0069 namespace detail {
0070 class HyperCube {
0071 public:
0072 explicit HyperCube(size_t rank)
0073 : offset(rank)
0074 , count(rank) {}
0075
0076 void cross(const std::array<size_t, 2>& range, size_t axis) {
0077 offset[axis] = range[0];
0078 count[axis] = range[1] - range[0];
0079 }
0080
0081 RegularHyperSlab asSlab() {
0082 return RegularHyperSlab(offset, count);
0083 }
0084
0085 private:
0086 std::vector<size_t> offset;
0087 std::vector<size_t> count;
0088 };
0089
0090 inline void build_hyper_slab(HyperSlab& slab, size_t , HyperCube& cube) {
0091 slab |= cube.asSlab();
0092 }
0093
0094 template <class... Slices>
0095 inline void build_hyper_slab(HyperSlab& slab,
0096 size_t axis,
0097 HyperCube& cube,
0098 const std::array<size_t, 2>& slice,
0099 const Slices&... higher_slices) {
0100 cube.cross(slice, axis);
0101 build_hyper_slab(slab, axis + 1, cube, higher_slices...);
0102 }
0103
0104 template <class... Slices>
0105 inline void build_hyper_slab(HyperSlab& slab,
0106 size_t axis,
0107 HyperCube& cube,
0108 const std::vector<std::array<size_t, 2>>& slices,
0109 const Slices&... higher_slices) {
0110 for (const auto& slice: slices) {
0111 build_hyper_slab(slab, axis, cube, slice, higher_slices...);
0112 }
0113 }
0114
0115 template <class... Slices>
0116 inline void build_hyper_slab(HyperSlab& slab,
0117 size_t axis,
0118 HyperCube& cube,
0119 const std::vector<size_t>& ids,
0120 const Slices&... higher_slices) {
0121 for (const auto& id: ids) {
0122 auto slice = std::array<size_t, 2>{id, id + 1};
0123 build_hyper_slab(slab, axis, cube, slice, higher_slices...);
0124 }
0125 }
0126
0127 template <class... Slices>
0128 inline void build_hyper_slab(HyperSlab& slab,
0129 size_t axis,
0130 HyperCube& cube,
0131 size_t id,
0132 const Slices&... higher_slices) {
0133 auto slice = std::array<size_t, 2>{id, id + 1};
0134 build_hyper_slab(slab, axis, cube, slice, higher_slices...);
0135 }
0136
0137 inline void compute_squashed_shape(size_t , std::vector<size_t>& ) {
0138
0139 }
0140
0141 template <class... Slices>
0142 inline void compute_squashed_shape(size_t axis,
0143 std::vector<size_t>& shape,
0144 const std::array<size_t, 2>& slice,
0145 const Slices&... higher_slices);
0146
0147 template <class... Slices>
0148 inline void compute_squashed_shape(size_t axis,
0149 std::vector<size_t>& shape,
0150 const std::vector<size_t>& points,
0151 const Slices&... higher_slices);
0152
0153 template <class... Slices>
0154 inline void compute_squashed_shape(size_t axis,
0155 std::vector<size_t>& shape,
0156 size_t point,
0157 const Slices&... higher_slices);
0158
0159 template <class... Slices>
0160 inline void compute_squashed_shape(size_t axis,
0161 std::vector<size_t>& shape,
0162 const std::vector<std::array<size_t, 2>>& slices,
0163 const Slices&... higher_slices);
0164
0165 template <class... Slices>
0166 inline void compute_squashed_shape(size_t axis,
0167 std::vector<size_t>& shape,
0168 const std::array<size_t, 2>& slice,
0169 const Slices&... higher_slices) {
0170 shape[axis] = slice[1] - slice[0];
0171 compute_squashed_shape(axis + 1, shape, higher_slices...);
0172 }
0173
0174 template <class... Slices>
0175 inline void compute_squashed_shape(size_t axis,
0176 std::vector<size_t>& shape,
0177 const std::vector<size_t>& points,
0178 const Slices&... higher_slices) {
0179 shape[axis] = points.size();
0180 compute_squashed_shape(axis + 1, shape, higher_slices...);
0181 }
0182
0183 template <class... Slices>
0184 inline void compute_squashed_shape(size_t axis,
0185 std::vector<size_t>& shape,
0186 const std::vector<std::array<size_t, 2>>& slices,
0187 const Slices&... higher_slices) {
0188 shape[axis] = 0;
0189 for (const auto& slice: slices) {
0190 shape[axis] += slice[1] - slice[0];
0191 }
0192 compute_squashed_shape(axis + 1, shape, higher_slices...);
0193 }
0194
0195 template <class... Slices>
0196 inline void compute_squashed_shape(size_t axis,
0197 std::vector<size_t>& shape,
0198 size_t ,
0199 const Slices&... higher_slices) {
0200 shape[axis] = 1;
0201 compute_squashed_shape(axis + 1, shape, higher_slices...);
0202 }
0203 }
0204
0205 template <class... Slices>
0206 inline ProductSet::ProductSet(const Slices&... slices) {
0207 auto rank = sizeof...(slices);
0208 detail::HyperCube cube(rank);
0209 detail::build_hyper_slab(slab, 0, cube, slices...);
0210
0211 shape = std::vector<size_t>(rank, size_t(0));
0212 detail::compute_squashed_shape(0, shape, slices...);
0213 }
0214
0215
0216 template <typename Derivate>
0217 inline Selection SliceTraits<Derivate>::select(const HyperSlab& hyper_slab,
0218 const DataSpace& memspace) const {
0219
0220
0221
0222
0223
0224
0225 const auto& slice = static_cast<const Derivate&>(*this);
0226 auto filespace = hyper_slab.apply(slice.getSpace());
0227
0228 return detail::make_selection(memspace, filespace, details::get_dataset(slice));
0229 }
0230
0231 template <typename Derivate>
0232 template <typename Impl>
0233 inline Selection SliceTraits<Derivate>::select(const HyperSlabInterface<Impl>& hyper_slab) const {
0234 const auto& slice = static_cast<const Derivate&>(*this);
0235 auto filespace = slice.getSpace();
0236 filespace = hyper_slab.apply(filespace);
0237
0238 const auto n_elements = detail::h5s_get_select_npoints(filespace.getId());
0239 auto memspace = DataSpace{static_cast<size_t>(n_elements)};
0240
0241 return detail::make_selection(memspace, filespace, details::get_dataset(slice));
0242 }
0243
0244 template <typename Derivate>
0245 inline Selection SliceTraits<Derivate>::select(const std::vector<size_t>& offset,
0246 const std::vector<size_t>& count,
0247 const std::vector<size_t>& stride,
0248 const std::vector<size_t>& block) const {
0249 auto slab = HyperSlab(RegularHyperSlab(offset, count, stride, block));
0250 auto memspace = DataSpace(count);
0251 return select(slab, memspace);
0252 }
0253
0254 template <typename Derivate>
0255 inline Selection SliceTraits<Derivate>::select(const std::vector<size_t>& columns) const {
0256 const auto& slice = static_cast<const Derivate&>(*this);
0257 const DataSpace& space = slice.getSpace();
0258 std::vector<size_t> dims = space.getDimensions();
0259
0260 if (dims.empty()) {
0261 throw DataSpaceException(
0262 "Invalid, zero-dimensional (scalar) dataspace encountered when "
0263 "selecting columns; must be atleast 1-dimensional.");
0264 }
0265
0266 std::vector<size_t> counts = dims;
0267 counts.back() = 1;
0268
0269 std::vector<size_t> offsets(dims.size(), 0);
0270
0271 HyperSlab slab;
0272 for (const auto& column: columns) {
0273 offsets.back() = column;
0274 slab |= RegularHyperSlab(offsets, counts);
0275 }
0276
0277 std::vector<size_t> memdims = dims;
0278 memdims.back() = columns.size();
0279
0280 return select(slab, DataSpace(memdims));
0281 }
0282
0283 template <typename Derivate>
0284 inline Selection SliceTraits<Derivate>::select(const ElementSet& elements) const {
0285 const auto& slice = static_cast<const Derivate&>(*this);
0286 const hsize_t* data = nullptr;
0287 const DataSpace space = slice.getSpace().clone();
0288 const std::size_t length = elements._ids.size();
0289 if (length % space.getNumberDimensions() != 0) {
0290 throw DataSpaceException(
0291 "Number of coordinates in elements picking "
0292 "should be a multiple of the dimensions.");
0293 }
0294 const std::size_t num_elements = length / space.getNumberDimensions();
0295 std::vector<hsize_t> raw_elements;
0296
0297
0298
0299 if (std::is_same<std::size_t, hsize_t>::value) {
0300
0301 data = reinterpret_cast<const hsize_t*>(elements._ids.data());
0302 } else {
0303 raw_elements.resize(length);
0304 std::copy(elements._ids.begin(), elements._ids.end(), raw_elements.begin());
0305 data = raw_elements.data();
0306 }
0307
0308 detail::h5s_select_elements(space.getId(), H5S_SELECT_SET, num_elements, data);
0309
0310 return detail::make_selection(DataSpace(num_elements), space, details::get_dataset(slice));
0311 }
0312
0313 template <typename Derivate>
0314 inline Selection SliceTraits<Derivate>::select(const ProductSet& product_set) const {
0315 return this->select(product_set.slab, DataSpace(product_set.shape));
0316 }
0317
0318
0319 template <typename Derivate>
0320 template <typename T>
0321 inline T SliceTraits<Derivate>::read(const DataTransferProps& xfer_props) const {
0322 T array;
0323 read(array, xfer_props);
0324 return array;
0325 }
0326
0327
0328 template <typename Derivate>
0329 template <typename T>
0330 inline void SliceTraits<Derivate>::read(T& array, const DataTransferProps& xfer_props) const {
0331 const auto& slice = static_cast<const Derivate&>(*this);
0332 const DataSpace& mem_space = slice.getMemSpace();
0333
0334 auto file_datatype = slice.getDataType();
0335
0336 const details::BufferInfo<T> buffer_info(
0337 file_datatype,
0338 [&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
0339 details::BufferInfo<T>::Operation::read);
0340
0341 if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
0342 std::ostringstream ss;
0343 ss << "Impossible to read DataSet of dimensions " << mem_space.getNumberDimensions()
0344 << " into arrays of dimensions: " << buffer_info.getMinRank() << "(min) to "
0345 << buffer_info.getMaxRank() << "(max)";
0346 throw DataSpaceException(ss.str());
0347 }
0348 auto dims = mem_space.getDimensions();
0349
0350 auto r = details::data_converter::get_reader<T>(dims, array, file_datatype);
0351 read_raw(r.getPointer(), buffer_info.data_type, xfer_props);
0352
0353 r.unserialize(array);
0354
0355 auto t = buffer_info.data_type;
0356 auto c = t.getClass();
0357 if (c == DataTypeClass::VarLen || t.isVariableStr()) {
0358 #if H5_VERSION_GE(1, 12, 0)
0359
0360 (void)
0361 detail::h5t_reclaim(t.getId(), mem_space.getId(), xfer_props.getId(), r.getPointer());
0362 #else
0363
0364 (void) detail::h5d_vlen_reclaim(t.getId(),
0365 mem_space.getId(),
0366 xfer_props.getId(),
0367 r.getPointer());
0368 #endif
0369 }
0370 }
0371
0372
0373 template <typename Derivate>
0374 template <typename T>
0375 inline void SliceTraits<Derivate>::read_raw(T* array,
0376 const DataType& mem_datatype,
0377 const DataTransferProps& xfer_props) const {
0378 static_assert(!std::is_const<T>::value,
0379 "read() requires a non-const structure to read data into");
0380
0381 const auto& slice = static_cast<const Derivate&>(*this);
0382
0383 detail::h5d_read(details::get_dataset(slice).getId(),
0384 mem_datatype.getId(),
0385 details::get_memspace_id(slice),
0386 slice.getSpace().getId(),
0387 xfer_props.getId(),
0388 static_cast<void*>(array));
0389 }
0390
0391
0392 template <typename Derivate>
0393 template <typename T>
0394 inline void SliceTraits<Derivate>::read_raw(T* array, const DataTransferProps& xfer_props) const {
0395 using element_type = typename details::inspector<T>::base_type;
0396 const DataType& mem_datatype = create_and_check_datatype<element_type>();
0397
0398 read_raw(array, mem_datatype, xfer_props);
0399 }
0400
0401
0402 template <typename Derivate>
0403 template <typename T>
0404 inline void SliceTraits<Derivate>::write(const T& buffer, const DataTransferProps& xfer_props) {
0405 const auto& slice = static_cast<const Derivate&>(*this);
0406 const DataSpace& mem_space = slice.getMemSpace();
0407 auto dims = mem_space.getDimensions();
0408
0409 auto file_datatype = slice.getDataType();
0410
0411 const details::BufferInfo<T> buffer_info(
0412 file_datatype,
0413 [&slice]() -> std::string { return details::get_dataset(slice).getPath(); },
0414 details::BufferInfo<T>::Operation::write);
0415
0416 if (!details::checkDimensions(mem_space, buffer_info.getMinRank(), buffer_info.getMaxRank())) {
0417 std::ostringstream ss;
0418 ss << "Impossible to write buffer with dimensions n = " << buffer_info.getRank(buffer)
0419 << "into dataset with dimensions " << details::format_vector(mem_space.getDimensions())
0420 << ".";
0421 throw DataSpaceException(ss.str());
0422 }
0423 auto w = details::data_converter::serialize<T>(buffer, dims, file_datatype);
0424 write_raw(w.getPointer(), buffer_info.data_type, xfer_props);
0425 }
0426
0427
0428 template <typename Derivate>
0429 template <typename T>
0430 inline void SliceTraits<Derivate>::write_raw(const T* buffer,
0431 const DataType& mem_datatype,
0432 const DataTransferProps& xfer_props) {
0433 const auto& slice = static_cast<const Derivate&>(*this);
0434
0435 detail::h5d_write(details::get_dataset(slice).getId(),
0436 mem_datatype.getId(),
0437 details::get_memspace_id(slice),
0438 slice.getSpace().getId(),
0439 xfer_props.getId(),
0440 static_cast<const void*>(buffer));
0441 }
0442
0443
0444 template <typename Derivate>
0445 template <typename T>
0446 inline void SliceTraits<Derivate>::write_raw(const T* buffer, const DataTransferProps& xfer_props) {
0447 using element_type = typename details::inspector<T>::base_type;
0448 const auto& mem_datatype = create_and_check_datatype<element_type>();
0449
0450 write_raw(buffer, mem_datatype, xfer_props);
0451 }
0452
0453 namespace detail {
0454 inline const DataSet& getDataSet(const Selection& selection) {
0455 return selection.getDataset();
0456 }
0457
0458 inline const DataSet& getDataSet(const DataSet& dataset) {
0459 return dataset;
0460 }
0461
0462 }
0463
0464 template <typename Derivate>
0465 inline Selection SliceTraits<Derivate>::squeezeMemSpace(const std::vector<size_t>& axes) const {
0466 auto slice = static_cast<const Derivate&>(*this);
0467 auto mem_dims = slice.getMemSpace().getDimensions();
0468 auto squeezed_dims = detail::squeeze(mem_dims, axes);
0469
0470 return detail::make_selection(DataSpace(squeezed_dims),
0471 slice.getSpace(),
0472 detail::getDataSet(slice));
0473 }
0474
0475 template <typename Derivate>
0476 inline Selection SliceTraits<Derivate>::reshapeMemSpace(const std::vector<size_t>& new_dims) const {
0477 auto slice = static_cast<const Derivate&>(*this);
0478
0479 detail::assert_compatible_spaces(slice.getMemSpace(), new_dims);
0480 return detail::make_selection(DataSpace(new_dims), slice.getSpace(), detail::getDataSet(slice));
0481 }
0482
0483 }