File indexing completed on 2025-04-19 08:55:33
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #pragma once
0011
0012 #include <type_traits>
0013 #include <cstring>
0014 #include <cassert>
0015 #include <vector>
0016 #include <array>
0017 #include <string>
0018 #include <numeric>
0019
0020 #include "../H5Reference.hpp"
0021
0022 #include "string_padding.hpp"
0023
0024 #include "H5Inspector_decl.hpp"
0025
0026
0027 namespace HighFive {
0028 namespace details {
0029
0030 inline bool checkDimensions(const std::vector<size_t>& dims, size_t n_dim_requested) {
0031 size_t n_dim_actual = dims.size();
0032
0033
0034 if (n_dim_requested == 0) {
0035 if (n_dim_actual == 0ul) {
0036 return true;
0037 }
0038
0039 return size_t(std::count(dims.begin(), dims.end(), 1ul)) == n_dim_actual;
0040 }
0041
0042
0043
0044 if (n_dim_actual < n_dim_requested) {
0045 return false;
0046 }
0047
0048
0049
0050 if (n_dim_requested == 1ul) {
0051 return n_dim_actual >= 1ul &&
0052 size_t(std::count(dims.begin(), dims.end(), 1ul)) >= n_dim_actual - 1ul;
0053 }
0054
0055
0056
0057 size_t n_dim_excess = n_dim_actual - n_dim_requested;
0058
0059 bool squeeze_back = true;
0060 for (size_t i = 1; i <= n_dim_excess; ++i) {
0061 if (dims[n_dim_actual - i] != 1) {
0062 squeeze_back = false;
0063 break;
0064 }
0065 }
0066
0067 return squeeze_back;
0068 }
0069
0070
0071 inline std::vector<size_t> squeezeDimensions(const std::vector<size_t>& dims,
0072 size_t n_dim_requested) {
0073 auto format_error_message = [&]() -> std::string {
0074 return "Can't interpret dims = " + format_vector(dims) + " as " +
0075 std::to_string(n_dim_requested) + "-dimensional.";
0076 };
0077
0078 if (n_dim_requested == 0) {
0079 if (!checkDimensions(dims, n_dim_requested)) {
0080 throw std::invalid_argument("Failed dimensions check: " + format_error_message());
0081 }
0082
0083 return {1ul};
0084 }
0085
0086 auto n_dim = dims.size();
0087 if (n_dim < n_dim_requested) {
0088 throw std::invalid_argument("Failed 'n_dim < n_dim_requested: " + format_error_message());
0089 }
0090
0091 if (n_dim_requested == 1ul) {
0092 size_t non_singleton_dim = size_t(-1);
0093 for (size_t i = 0; i < n_dim; ++i) {
0094 if (dims[i] != 1ul) {
0095 if (non_singleton_dim == size_t(-1)) {
0096 non_singleton_dim = i;
0097 } else {
0098 throw std::invalid_argument("Failed one-dimensional: " +
0099 format_error_message());
0100 }
0101 }
0102 }
0103
0104 return {dims[std::min(non_singleton_dim, n_dim - 1)]};
0105 }
0106
0107 size_t n_dim_excess = dims.size() - n_dim_requested;
0108 for (size_t i = 1; i <= n_dim_excess; ++i) {
0109 if (dims[n_dim - i] != 1) {
0110 throw std::invalid_argument("Failed stripping from back:" + format_error_message());
0111 }
0112 }
0113
0114 return std::vector<size_t>(dims.begin(),
0115 dims.end() - static_cast<std::ptrdiff_t>(n_dim_excess));
0116 }
0117 }
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 namespace details {
0160 template <typename T>
0161 struct type_helper {
0162 using type = unqualified_t<T>;
0163 using base_type = unqualified_t<T>;
0164 using hdf5_type = base_type;
0165
0166 static constexpr size_t ndim = 0;
0167 static constexpr size_t recursive_ndim = ndim;
0168 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
0169
0170 static std::vector<size_t> getDimensions(const type& ) {
0171 return {};
0172 }
0173
0174 static size_t getSizeVal(const type& val) {
0175 return compute_total_size(getDimensions(val));
0176 }
0177
0178 static size_t getSize(const std::vector<size_t>& dims) {
0179 return compute_total_size(dims);
0180 }
0181
0182 static void prepare(type& , const std::vector<size_t>& ) {}
0183
0184 static hdf5_type* data(type& val) {
0185 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0186 return &val;
0187 }
0188
0189 static const hdf5_type* data(const type& val) {
0190 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0191 return &val;
0192 }
0193
0194 static void serialize(const type& val, hdf5_type* m) {
0195 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0196 *m = val;
0197 }
0198
0199 static void unserialize(const hdf5_type* vec,
0200 const std::vector<size_t>& ,
0201 type& val) {
0202 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0203 val = vec[0];
0204 }
0205 };
0206
0207 template <typename T>
0208 struct inspector: type_helper<T> {};
0209
0210 enum class Boolean : int8_t {
0211 HighFiveFalse = 0,
0212 HighFiveTrue = 1,
0213 };
0214
0215 template <>
0216 struct inspector<bool>: type_helper<bool> {
0217 using base_type = Boolean;
0218 using hdf5_type = int8_t;
0219
0220 static constexpr bool is_trivially_copyable = false;
0221
0222 static hdf5_type* data(type& ) {
0223 throw DataSpaceException("A boolean cannot be read directly.");
0224 }
0225
0226 static const hdf5_type* data(const type& ) {
0227 throw DataSpaceException("A boolean cannot be written directly.");
0228 }
0229
0230 static void unserialize(const hdf5_type* vec,
0231 const std::vector<size_t>& ,
0232 type& val) {
0233 val = vec[0] != 0 ? true : false;
0234 }
0235
0236 static void serialize(const type& val, hdf5_type* m) {
0237 *m = val ? 1 : 0;
0238 }
0239 };
0240
0241 template <>
0242 struct inspector<std::string>: type_helper<std::string> {
0243 using hdf5_type = const char*;
0244
0245 static hdf5_type* data(type& ) {
0246 throw DataSpaceException("A std::string cannot be read directly.");
0247 }
0248
0249 static const hdf5_type* data(const type& ) {
0250 throw DataSpaceException("A std::string cannot be written directly.");
0251 }
0252
0253 template <class It>
0254 static void serialize(const type& val, It m) {
0255 (*m).assign(val.data(), val.size(), StringPadding::NullTerminated);
0256 }
0257
0258 template <class It>
0259 static void unserialize(const It& vec, const std::vector<size_t>& , type& val) {
0260 const auto& view = *vec;
0261 val.assign(view.data(), view.length());
0262 }
0263 };
0264
0265 template <>
0266 struct inspector<Reference>: type_helper<Reference> {
0267 using hdf5_type = hobj_ref_t;
0268
0269 static constexpr bool is_trivially_copyable = false;
0270
0271 static hdf5_type* data(type& ) {
0272 throw DataSpaceException("A Reference cannot be read directly.");
0273 }
0274
0275 static const hdf5_type* data(const type& ) {
0276 throw DataSpaceException("A Reference cannot be written directly.");
0277 }
0278
0279 static void serialize(const type& val, hdf5_type* m) {
0280 hobj_ref_t ref;
0281 val.create_ref(&ref);
0282 *m = ref;
0283 }
0284
0285 static void unserialize(const hdf5_type* vec,
0286 const std::vector<size_t>& ,
0287 type& val) {
0288 val = type{vec[0]};
0289 }
0290 };
0291
0292 template <size_t N>
0293 struct inspector<deprecated::FixedLenStringArray<N>> {
0294 using type = deprecated::FixedLenStringArray<N>;
0295 using value_type = char*;
0296 using base_type = deprecated::FixedLenStringArray<N>;
0297 using hdf5_type = char;
0298
0299 static constexpr size_t ndim = 1;
0300 static constexpr size_t recursive_ndim = ndim;
0301 static constexpr bool is_trivially_copyable = false;
0302
0303 static std::vector<size_t> getDimensions(const type& val) {
0304 return std::vector<size_t>{val.size()};
0305 }
0306
0307 static size_t getSizeVal(const type& val) {
0308 return N * compute_total_size(getDimensions(val));
0309 }
0310
0311 static size_t getSize(const std::vector<size_t>& dims) {
0312 return N * compute_total_size(dims);
0313 }
0314
0315 static void prepare(type& , const std::vector<size_t>& dims) {
0316 if (dims[0] > N) {
0317 std::ostringstream os;
0318 os << "Size of FixedlenStringArray (" << N << ") is too small for dims (" << dims[0]
0319 << ").";
0320 throw DataSpaceException(os.str());
0321 }
0322 }
0323
0324 static hdf5_type* data(type& val) {
0325 return val.data();
0326 }
0327
0328 static const hdf5_type* data(const type& val) {
0329 return val.data();
0330 }
0331
0332 static void serialize(const type& val, hdf5_type* m) {
0333 for (size_t i = 0; i < val.size(); ++i) {
0334 std::memcpy(m + i * N, val[i], N);
0335 }
0336 }
0337
0338 static void unserialize(const hdf5_type* vec, const std::vector<size_t>& dims, type& val) {
0339 for (size_t i = 0; i < dims[0]; ++i) {
0340 std::array<char, N> s;
0341 std::memcpy(s.data(), vec + (i * N), N);
0342 val.push_back(s);
0343 }
0344 }
0345 };
0346
0347 template <typename T>
0348 struct inspector<std::vector<T>> {
0349 using type = std::vector<T>;
0350 using value_type = unqualified_t<T>;
0351 using base_type = typename inspector<value_type>::base_type;
0352 using hdf5_type = typename inspector<value_type>::hdf5_type;
0353
0354 static constexpr size_t ndim = 1;
0355 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
0356 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0357 inspector<value_type>::is_trivially_copyable;
0358
0359 static std::vector<size_t> getDimensions(const type& val) {
0360 std::vector<size_t> sizes(recursive_ndim, 1ul);
0361 sizes[0] = val.size();
0362 if (!val.empty()) {
0363 auto s = inspector<value_type>::getDimensions(val[0]);
0364 assert(s.size() + ndim == sizes.size());
0365 for (size_t i = 0; i < s.size(); ++i) {
0366 sizes[i + ndim] = s[i];
0367 }
0368 }
0369 return sizes;
0370 }
0371
0372 static size_t getSizeVal(const type& val) {
0373 return compute_total_size(getDimensions(val));
0374 }
0375
0376 static size_t getSize(const std::vector<size_t>& dims) {
0377 return compute_total_size(dims);
0378 }
0379
0380 static void prepare(type& val, const std::vector<size_t>& dims) {
0381 val.resize(dims[0]);
0382 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0383 for (auto&& e: val) {
0384 inspector<value_type>::prepare(e, next_dims);
0385 }
0386 }
0387
0388 static hdf5_type* data(type& val) {
0389 return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
0390 }
0391
0392 static const hdf5_type* data(const type& val) {
0393 return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
0394 }
0395
0396 template <class It>
0397 static void serialize(const type& val, It m) {
0398 if (!val.empty()) {
0399 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
0400 for (auto&& e: val) {
0401 inspector<value_type>::serialize(e, m);
0402 m += subsize;
0403 }
0404 }
0405 }
0406
0407 template <class It>
0408 static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
0409 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0410 size_t next_size = compute_total_size(next_dims);
0411 for (size_t i = 0; i < dims[0]; ++i) {
0412 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
0413 }
0414 }
0415 };
0416
0417 template <>
0418 struct inspector<std::vector<bool>> {
0419 using type = std::vector<bool>;
0420 using value_type = bool;
0421 using base_type = Boolean;
0422 using hdf5_type = uint8_t;
0423
0424 static constexpr size_t ndim = 1;
0425 static constexpr size_t recursive_ndim = ndim;
0426 static constexpr bool is_trivially_copyable = false;
0427
0428 static std::vector<size_t> getDimensions(const type& val) {
0429 std::vector<size_t> sizes{val.size()};
0430 return sizes;
0431 }
0432
0433 static size_t getSizeVal(const type& val) {
0434 return val.size();
0435 }
0436
0437 static size_t getSize(const std::vector<size_t>& dims) {
0438 if (dims.size() > 1) {
0439 throw DataSpaceException("std::vector<bool> is only 1 dimension.");
0440 }
0441 return dims[0];
0442 }
0443
0444 static void prepare(type& val, const std::vector<size_t>& dims) {
0445 if (dims.size() > 1) {
0446 throw DataSpaceException("std::vector<bool> is only 1 dimension.");
0447 }
0448 val.resize(dims[0]);
0449 }
0450
0451 static hdf5_type* data(type& ) {
0452 throw DataSpaceException("A std::vector<bool> cannot be read directly.");
0453 }
0454
0455 static const hdf5_type* data(const type& ) {
0456 throw DataSpaceException("A std::vector<bool> cannot be written directly.");
0457 }
0458
0459 static void serialize(const type& val, hdf5_type* m) {
0460 for (size_t i = 0; i < val.size(); ++i) {
0461 m[i] = val[i] ? 1 : 0;
0462 }
0463 }
0464
0465 static void unserialize(const hdf5_type* vec_align,
0466 const std::vector<size_t>& dims,
0467 type& val) {
0468 for (size_t i = 0; i < dims[0]; ++i) {
0469 val[i] = vec_align[i] != 0 ? true : false;
0470 }
0471 }
0472 };
0473
0474 template <typename T, size_t N>
0475 struct inspector<std::array<T, N>> {
0476 using type = std::array<T, N>;
0477 using value_type = unqualified_t<T>;
0478 using base_type = typename inspector<value_type>::base_type;
0479 using hdf5_type = typename inspector<value_type>::hdf5_type;
0480
0481 static constexpr size_t ndim = 1;
0482 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
0483 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0484 sizeof(type) == N * sizeof(T) &&
0485 inspector<value_type>::is_trivially_copyable;
0486
0487 static std::vector<size_t> getDimensions(const type& val) {
0488 std::vector<size_t> sizes{N};
0489 if (!val.empty()) {
0490 auto s = inspector<value_type>::getDimensions(val[0]);
0491 sizes.insert(sizes.end(), s.begin(), s.end());
0492 }
0493 return sizes;
0494 }
0495
0496 static size_t getSizeVal(const type& val) {
0497 return compute_total_size(getDimensions(val));
0498 }
0499
0500 static size_t getSize(const std::vector<size_t>& dims) {
0501 return compute_total_size(dims);
0502 }
0503
0504 static void prepare(type& val, const std::vector<size_t>& dims) {
0505 if (dims[0] > N) {
0506 std::ostringstream os;
0507 os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ").";
0508 throw DataSpaceException(os.str());
0509 }
0510
0511 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0512 for (auto&& e: val) {
0513 inspector<value_type>::prepare(e, next_dims);
0514 }
0515 }
0516
0517 static hdf5_type* data(type& val) {
0518 return inspector<value_type>::data(val[0]);
0519 }
0520
0521 static const hdf5_type* data(const type& val) {
0522 return inspector<value_type>::data(val[0]);
0523 }
0524
0525 template <class It>
0526 static void serialize(const type& val, It m) {
0527 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
0528 for (auto& e: val) {
0529 inspector<value_type>::serialize(e, m);
0530 m += subsize;
0531 }
0532 }
0533
0534 template <class It>
0535 static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
0536 if (dims[0] != N) {
0537 std::ostringstream os;
0538 os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with "
0539 << N << " elements.";
0540 throw DataSpaceException(os.str());
0541 }
0542 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0543 size_t next_size = compute_total_size(next_dims);
0544 for (size_t i = 0; i < dims[0]; ++i) {
0545 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
0546 }
0547 }
0548 };
0549
0550
0551 template <typename T>
0552 struct inspector<T*> {
0553 using type = T*;
0554 using value_type = unqualified_t<T>;
0555 using base_type = typename inspector<value_type>::base_type;
0556 using hdf5_type = typename inspector<value_type>::hdf5_type;
0557
0558 static constexpr size_t ndim = 1;
0559 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
0560 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0561 inspector<value_type>::is_trivially_copyable;
0562
0563 static size_t getSizeVal(const type& ) {
0564 throw DataSpaceException("Not possible to have size of a T*");
0565 }
0566
0567 static std::vector<size_t> getDimensions(const type& ) {
0568 throw DataSpaceException("Not possible to have size of a T*");
0569 }
0570
0571 static const hdf5_type* data(const type& val) {
0572 return reinterpret_cast<const hdf5_type*>(val);
0573 }
0574
0575
0576
0577 static void serialize(const type& , hdf5_type* ) {
0578 throw DataSpaceException("Not possible to serialize a T*");
0579 }
0580 };
0581
0582
0583 template <typename T, size_t N>
0584 struct inspector<T[N]> {
0585 using type = T[N];
0586 using value_type = unqualified_t<T>;
0587 using base_type = typename inspector<value_type>::base_type;
0588 using hdf5_type = typename inspector<value_type>::hdf5_type;
0589
0590 static constexpr size_t ndim = 1;
0591 static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
0592 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0593 inspector<value_type>::is_trivially_copyable;
0594
0595 static void prepare(type& val, const std::vector<size_t>& dims) {
0596 if (dims.size() < 1) {
0597 throw DataSpaceException("Invalid 'dims', must be at least 1 dimensional.");
0598 }
0599
0600 if (dims[0] != N) {
0601 throw DataSpaceException("Dimensions mismatch.");
0602 }
0603
0604 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0605 for (size_t i = 0; i < dims[0]; ++i) {
0606 inspector<value_type>::prepare(val[i], next_dims);
0607 }
0608 }
0609
0610 static size_t getSizeVal(const type& val) {
0611 return compute_total_size(getDimensions(val));
0612 }
0613
0614 static std::vector<size_t> getDimensions(const type& val) {
0615 std::vector<size_t> sizes{N};
0616 if (N > 0) {
0617 auto s = inspector<value_type>::getDimensions(val[0]);
0618 sizes.insert(sizes.end(), s.begin(), s.end());
0619 }
0620 return sizes;
0621 }
0622
0623 static const hdf5_type* data(const type& val) {
0624 return inspector<value_type>::data(val[0]);
0625 }
0626
0627 static hdf5_type* data(type& val) {
0628 return inspector<value_type>::data(val[0]);
0629 }
0630
0631
0632
0633 static void serialize(const type& val, hdf5_type* m) {
0634 size_t subsize = inspector<value_type>::getSizeVal(val[0]);
0635 for (size_t i = 0; i < N; ++i) {
0636 inspector<value_type>::serialize(val[i], m + i * subsize);
0637 }
0638 }
0639 };
0640
0641 }
0642 }
0643
0644 #ifdef H5_USE_BOOST
0645 #include <highfive/boost.hpp>
0646 #endif
0647
0648 #ifdef H5_USE_EIGEN
0649 #include <highfive/eigen.hpp>
0650 #endif