File indexing completed on 2026-06-11 08:30:59
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,
0031 size_t min_dim_requested,
0032 size_t max_dim_requested) {
0033 if (min_dim_requested <= dims.size() && dims.size() <= max_dim_requested) {
0034 return true;
0035 }
0036
0037
0038
0039
0040 size_t n_elements = compute_total_size(dims);
0041 return n_elements == 1 && min_dim_requested == 0;
0042 }
0043
0044 }
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084 namespace details {
0085 template <typename T>
0086 struct type_helper {
0087 using type = unqualified_t<T>;
0088 using base_type = unqualified_t<T>;
0089 using hdf5_type = base_type;
0090
0091 static constexpr size_t ndim = 0;
0092 static constexpr size_t min_ndim = ndim;
0093 static constexpr size_t max_ndim = ndim;
0094
0095 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
0096 static constexpr bool is_trivially_nestable = is_trivially_copyable;
0097
0098 static size_t getRank(const type& ) {
0099 return ndim;
0100 }
0101
0102 static std::vector<size_t> getDimensions(const type& ) {
0103 return {};
0104 }
0105
0106 static void prepare(type& , const std::vector<size_t>& ) {}
0107
0108 static hdf5_type* data(type& val) {
0109 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0110 return &val;
0111 }
0112
0113 static const hdf5_type* data(const type& val) {
0114 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0115 return &val;
0116 }
0117
0118 static void serialize(const type& val, const std::vector<size_t>& , hdf5_type* m) {
0119 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0120 *m = val;
0121 }
0122
0123 static void unserialize(const hdf5_type* vec,
0124 const std::vector<size_t>& ,
0125 type& val) {
0126 static_assert(is_trivially_copyable, "The type is not trivially copyable");
0127 val = vec[0];
0128 }
0129 };
0130
0131 template <typename T>
0132 struct inspector: type_helper<T> {};
0133
0134 enum class Boolean : int8_t {
0135 HighFiveFalse = 0,
0136 HighFiveTrue = 1,
0137 };
0138
0139 template <>
0140 struct inspector<bool>: type_helper<bool> {
0141 using base_type = Boolean;
0142 using hdf5_type = int8_t;
0143
0144 static constexpr bool is_trivially_copyable = false;
0145 static constexpr bool is_trivially_nestable = false;
0146
0147 static hdf5_type* data(type& ) {
0148 throw DataSpaceException("A boolean cannot be read directly.");
0149 }
0150
0151 static const hdf5_type* data(const type& ) {
0152 throw DataSpaceException("A boolean cannot be written directly.");
0153 }
0154
0155 static void unserialize(const hdf5_type* vec,
0156 const std::vector<size_t>& ,
0157 type& val) {
0158 val = vec[0] != 0;
0159 }
0160
0161 static void serialize(const type& val, const std::vector<size_t>& , hdf5_type* m) {
0162 *m = val ? 1 : 0;
0163 }
0164 };
0165
0166 template <>
0167 struct inspector<std::string>: type_helper<std::string> {
0168 using hdf5_type = const char*;
0169
0170 static hdf5_type* data(type& ) {
0171 throw DataSpaceException("A std::string cannot be read directly.");
0172 }
0173
0174 static const hdf5_type* data(const type& ) {
0175 throw DataSpaceException("A std::string cannot be written directly.");
0176 }
0177
0178 template <class It>
0179 static void serialize(const type& val, const std::vector<size_t>& , It m) {
0180 (*m).assign(val.data(), val.size(), StringPadding::NullTerminated);
0181 }
0182
0183 template <class It>
0184 static void unserialize(const It& vec, const std::vector<size_t>& , type& val) {
0185 const auto& view = *vec;
0186 val.assign(view.data(), view.length());
0187 }
0188 };
0189
0190 template <>
0191 struct inspector<Reference>: type_helper<Reference> {
0192 using hdf5_type = hobj_ref_t;
0193
0194 static constexpr bool is_trivially_copyable = false;
0195 static constexpr bool is_trivially_nestable = false;
0196
0197 static hdf5_type* data(type& ) {
0198 throw DataSpaceException("A Reference cannot be read directly.");
0199 }
0200
0201 static const hdf5_type* data(const type& ) {
0202 throw DataSpaceException("A Reference cannot be written directly.");
0203 }
0204
0205 static void serialize(const type& val, const std::vector<size_t>& , hdf5_type* m) {
0206 hobj_ref_t ref;
0207 val.create_ref(&ref);
0208 *m = ref;
0209 }
0210
0211 static void unserialize(const hdf5_type* vec,
0212 const std::vector<size_t>& ,
0213 type& val) {
0214 val = type{vec[0]};
0215 }
0216 };
0217
0218 template <typename T>
0219 struct inspector<std::vector<T>> {
0220 using type = std::vector<T>;
0221 using value_type = unqualified_t<T>;
0222 using base_type = typename inspector<value_type>::base_type;
0223 using hdf5_type = typename inspector<value_type>::hdf5_type;
0224
0225 static constexpr size_t ndim = 1;
0226 static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
0227 static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
0228
0229 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0230 inspector<value_type>::is_trivially_nestable;
0231 static constexpr bool is_trivially_nestable = false;
0232
0233 static size_t getRank(const type& val) {
0234 if (!val.empty()) {
0235 return ndim + inspector<value_type>::getRank(val[0]);
0236 } else {
0237 return min_ndim;
0238 }
0239 }
0240
0241 static std::vector<size_t> getDimensions(const type& val) {
0242 auto rank = getRank(val);
0243 std::vector<size_t> sizes(rank, 1ul);
0244 sizes[0] = val.size();
0245 if (!val.empty()) {
0246 auto s = inspector<value_type>::getDimensions(val[0]);
0247 for (size_t i = 0; i < s.size(); ++i) {
0248 sizes[i + ndim] = s[i];
0249 }
0250 }
0251 return sizes;
0252 }
0253
0254 static void prepare(type& val, const std::vector<size_t>& dims) {
0255 val.resize(dims[0]);
0256 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0257 for (auto&& e: val) {
0258 inspector<value_type>::prepare(e, next_dims);
0259 }
0260 }
0261
0262 static hdf5_type* data(type& val) {
0263 return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
0264 }
0265
0266 static const hdf5_type* data(const type& val) {
0267 return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
0268 }
0269
0270 template <class It>
0271 static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
0272 if (!val.empty()) {
0273 auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
0274 size_t subsize = compute_total_size(subdims);
0275 for (auto&& e: val) {
0276 inspector<value_type>::serialize(e, subdims, m);
0277 m += subsize;
0278 }
0279 }
0280 }
0281
0282 template <class It>
0283 static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
0284 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0285 size_t next_size = compute_total_size(next_dims);
0286 for (size_t i = 0; i < dims[0]; ++i) {
0287 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
0288 }
0289 }
0290 };
0291
0292 template <>
0293 struct inspector<std::vector<bool>> {
0294 using type = std::vector<bool>;
0295 using value_type = bool;
0296 using base_type = Boolean;
0297 using hdf5_type = uint8_t;
0298
0299 static constexpr size_t ndim = 1;
0300 static constexpr size_t min_ndim = ndim;
0301 static constexpr size_t max_ndim = ndim;
0302
0303 static constexpr bool is_trivially_copyable = false;
0304 static constexpr bool is_trivially_nestable = false;
0305
0306 static size_t getRank(const type& ) {
0307 return ndim;
0308 }
0309
0310 static std::vector<size_t> getDimensions(const type& val) {
0311 std::vector<size_t> sizes{val.size()};
0312 return sizes;
0313 }
0314
0315 static void prepare(type& val, const std::vector<size_t>& dims) {
0316 if (dims.size() > 1) {
0317 throw DataSpaceException("std::vector<bool> is only 1 dimension.");
0318 }
0319 val.resize(dims[0]);
0320 }
0321
0322 static hdf5_type* data(type& ) {
0323 throw DataSpaceException("A std::vector<bool> cannot be read directly.");
0324 }
0325
0326 static const hdf5_type* data(const type& ) {
0327 throw DataSpaceException("A std::vector<bool> cannot be written directly.");
0328 }
0329
0330 static void serialize(const type& val, const std::vector<size_t>& , hdf5_type* m) {
0331 for (size_t i = 0; i < val.size(); ++i) {
0332 m[i] = val[i] ? 1 : 0;
0333 }
0334 }
0335
0336 static void unserialize(const hdf5_type* vec_align,
0337 const std::vector<size_t>& dims,
0338 type& val) {
0339 for (size_t i = 0; i < dims[0]; ++i) {
0340 val[i] = vec_align[i] != 0;
0341 }
0342 }
0343 };
0344
0345 template <typename T, size_t N>
0346 struct inspector<std::array<T, N>> {
0347 using type = std::array<T, N>;
0348 using value_type = unqualified_t<T>;
0349 using base_type = typename inspector<value_type>::base_type;
0350 using hdf5_type = typename inspector<value_type>::hdf5_type;
0351
0352 static constexpr size_t ndim = 1;
0353 static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
0354 static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
0355
0356 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0357 inspector<value_type>::is_trivially_nestable;
0358 static constexpr bool is_trivially_nestable = (sizeof(type) == N * sizeof(T)) &&
0359 is_trivially_copyable;
0360
0361 static size_t getRank(const type& val) {
0362 return ndim + inspector<value_type>::getRank(val[0]);
0363 }
0364
0365 static std::vector<size_t> getDimensions(const type& val) {
0366 std::vector<size_t> sizes{N};
0367 auto s = inspector<value_type>::getDimensions(val[0]);
0368 sizes.insert(sizes.end(), s.begin(), s.end());
0369 return sizes;
0370 }
0371
0372 static void prepare(type& val, const std::vector<size_t>& dims) {
0373 if (dims[0] > N) {
0374 std::ostringstream os;
0375 os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ").";
0376 throw DataSpaceException(os.str());
0377 }
0378
0379 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0380 for (auto&& e: val) {
0381 inspector<value_type>::prepare(e, next_dims);
0382 }
0383 }
0384
0385 static hdf5_type* data(type& val) {
0386 return inspector<value_type>::data(val[0]);
0387 }
0388
0389 static const hdf5_type* data(const type& val) {
0390 return inspector<value_type>::data(val[0]);
0391 }
0392
0393 template <class It>
0394 static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
0395 auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
0396 size_t subsize = compute_total_size(subdims);
0397 for (auto& e: val) {
0398 inspector<value_type>::serialize(e, subdims, m);
0399 m += subsize;
0400 }
0401 }
0402
0403 template <class It>
0404 static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
0405 if (dims[0] != N) {
0406 std::ostringstream os;
0407 os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with "
0408 << N << " elements.";
0409 throw DataSpaceException(os.str());
0410 }
0411 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0412 size_t next_size = compute_total_size(next_dims);
0413 for (size_t i = 0; i < val.size(); ++i) {
0414 inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
0415 }
0416 }
0417 };
0418
0419
0420
0421 template <typename T>
0422 struct inspector<T*> {
0423 using type = T*;
0424 using value_type = unqualified_t<T>;
0425 using base_type = typename inspector<value_type>::base_type;
0426 using hdf5_type = typename inspector<value_type>::hdf5_type;
0427
0428 static constexpr size_t ndim = 1;
0429 static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
0430 static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
0431
0432 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0433 inspector<value_type>::is_trivially_nestable;
0434 static constexpr bool is_trivially_nestable = false;
0435
0436 static size_t getRank(const type& val) {
0437 if (val != nullptr) {
0438 return ndim + inspector<value_type>::getRank(val[0]);
0439 } else {
0440 return min_ndim;
0441 }
0442 }
0443
0444 static std::vector<size_t> getDimensions(const type& ) {
0445 throw DataSpaceException("Not possible to have size of a T*");
0446 }
0447
0448 static const hdf5_type* data(const type& val) {
0449 return reinterpret_cast<const hdf5_type*>(val);
0450 }
0451
0452
0453
0454 static void serialize(const type& ,
0455 const std::vector<size_t>& ,
0456 hdf5_type* ) {
0457 throw DataSpaceException("Not possible to serialize a T*");
0458 }
0459 };
0460
0461
0462 template <typename T, size_t N>
0463 struct inspector<T[N]> {
0464 using type = T[N];
0465 using value_type = unqualified_t<T>;
0466 using base_type = typename inspector<value_type>::base_type;
0467 using hdf5_type = typename inspector<value_type>::hdf5_type;
0468
0469 static constexpr size_t ndim = 1;
0470 static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
0471 static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
0472
0473 static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
0474 inspector<value_type>::is_trivially_nestable;
0475 static constexpr bool is_trivially_nestable = is_trivially_copyable;
0476
0477 static void prepare(type& val, const std::vector<size_t>& dims) {
0478 if (dims.empty()) {
0479 throw DataSpaceException("Invalid 'dims', must be at least 1 dimensional.");
0480 }
0481
0482 if (dims[0] != N) {
0483 throw DataSpaceException("Dimensions mismatch.");
0484 }
0485
0486 std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
0487 for (size_t i = 0; i < N; ++i) {
0488 inspector<value_type>::prepare(val[i], next_dims);
0489 }
0490 }
0491
0492 static size_t getRank(const type& val) {
0493 return ndim + inspector<value_type>::getRank(val[0]);
0494 }
0495
0496 static std::vector<size_t> getDimensions(const type& val) {
0497 std::vector<size_t> sizes{N};
0498 auto s = inspector<value_type>::getDimensions(val[0]);
0499 sizes.insert(sizes.end(), s.begin(), s.end());
0500 return sizes;
0501 }
0502
0503 static const hdf5_type* data(const type& val) {
0504 return inspector<value_type>::data(val[0]);
0505 }
0506
0507 static hdf5_type* data(type& val) {
0508 return inspector<value_type>::data(val[0]);
0509 }
0510
0511
0512
0513 static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
0514 auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
0515 size_t subsize = compute_total_size(subdims);
0516 for (size_t i = 0; i < N; ++i) {
0517 inspector<value_type>::serialize(val[i], subdims, m + i * subsize);
0518 }
0519 }
0520 };
0521
0522
0523 }
0524 }