Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-06-11 08:30:59

0001 /*
0002  *  Copyright (c) 2022 Blue Brain Project
0003  *
0004  *  Distributed under the Boost Software License, Version 1.0.
0005  *    (See accompanying file LICENSE_1_0.txt or copy at
0006  *          http://www.boost.org/LICENSE_1_0.txt)
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     // Scalar values still support broadcasting
0039     // into arrays with one element.
0040     size_t n_elements = compute_total_size(dims);
0041     return n_elements == 1 && min_dim_requested == 0;
0042 }
0043 
0044 }  // namespace details
0045 
0046 
0047 /*****
0048 inspector<T> {
0049     using type = T
0050     // base_type is the base type inside c++ (e.g. std::vector<int> => int)
0051     using base_type
0052     // hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector<std::string> => const char*)
0053     using hdf5_type
0054 
0055     // Is the inner type trivially copyable for optimisation
0056     // If this value is true: data() is mandatory
0057     // If this value is false: serialize, unserialize are mandatory
0058     static constexpr bool is_trivially_copyable
0059 
0060     // Is this type trivially nestable, i.e. is type[n] a contiguous
0061     // array of `base_type[N]`?
0062     static constexpr bool is_trivially_nestable
0063 
0064     // Reading:
0065     // Allocate the value following dims (should be recursive)
0066     static void prepare(type& val, const std::vector<std::size_t> dims)
0067     // Return a pointer of the first value of val (for reading)
0068     static hdf5_type* data(type& val)
0069     // Take a serialized vector 'in', some dims and copy value to val (for reading)
0070     static void unserialize(const hdf5_type* in, const std::vector<size_t>&i, type& val)
0071 
0072 
0073     // Writing:
0074     // Return a point of the first value of val
0075     static const hdf5_type* data(const type& val)
0076     // Take a val and serialize it inside 'out'
0077     static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* out)
0078     // Return an array of dimensions of the space needed for writing val
0079     static std::vector<size_t> getDimensions(const type& val)
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& /* val */) {
0099         return ndim;
0100     }
0101 
0102     static std::vector<size_t> getDimensions(const type& /* val */) {
0103         return {};
0104     }
0105 
0106     static void prepare(type& /* val */, const std::vector<size_t>& /* dims */) {}
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>& /* dims*/, 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>& /* dims */,
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& /* val */) {
0148         throw DataSpaceException("A boolean cannot be read directly.");
0149     }
0150 
0151     static const hdf5_type* data(const type& /* val */) {
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>& /* dims */,
0157                             type& val) {
0158         val = vec[0] != 0;
0159     }
0160 
0161     static void serialize(const type& val, const std::vector<size_t>& /* dims*/, 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& /* val */) {
0171         throw DataSpaceException("A std::string cannot be read directly.");
0172     }
0173 
0174     static const hdf5_type* data(const type& /* val */) {
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>& /* dims*/, 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>& /* dims */, 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& /* val */) {
0198         throw DataSpaceException("A Reference cannot be read directly.");
0199     }
0200 
0201     static const hdf5_type* data(const type& /* val */) {
0202         throw DataSpaceException("A Reference cannot be written directly.");
0203     }
0204 
0205     static void serialize(const type& val, const std::vector<size_t>& /* dims*/, 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>& /* dims */,
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& /* val */) {
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& /* val */) {
0323         throw DataSpaceException("A std::vector<bool> cannot be read directly.");
0324     }
0325 
0326     static const hdf5_type* data(const type& /* val */) {
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>& /* dims*/, 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 // Cannot be use for reading
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& /* val */) {
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     /* it works because there is only T[][][] currently
0453        we will fix it one day */
0454     static void serialize(const type& /* val */,
0455                           const std::vector<size_t>& /* dims*/,
0456                           hdf5_type* /* m */) {
0457         throw DataSpaceException("Not possible to serialize a T*");
0458     }
0459 };
0460 
0461 // Cannot be use for reading
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     /* it works because there is only T[][][] currently
0512        we will fix it one day */
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 }  // namespace details
0524 }  // namespace HighFive