mirror of
https://git.gfz-potsdam.de/naaice/poet.git
synced 2025-12-16 12:54:50 +01:00
525 lines
17 KiB
C++
525 lines
17 KiB
C++
/*
|
|
* Copyright (c) 2022 Blue Brain Project
|
|
*
|
|
* Distributed under the Boost Software License, Version 1.0.
|
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
|
* http://www.boost.org/LICENSE_1_0.txt)
|
|
*
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <type_traits>
|
|
#include <cstring>
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <array>
|
|
#include <string>
|
|
#include <numeric>
|
|
|
|
#include "../H5Reference.hpp"
|
|
|
|
#include "string_padding.hpp"
|
|
|
|
#include "H5Inspector_decl.hpp"
|
|
|
|
|
|
namespace HighFive {
|
|
namespace details {
|
|
|
|
inline bool checkDimensions(const std::vector<size_t>& dims,
|
|
size_t min_dim_requested,
|
|
size_t max_dim_requested) {
|
|
if (min_dim_requested <= dims.size() && dims.size() <= max_dim_requested) {
|
|
return true;
|
|
}
|
|
|
|
|
|
// Scalar values still support broadcasting
|
|
// into arrays with one element.
|
|
size_t n_elements = compute_total_size(dims);
|
|
return n_elements == 1 && min_dim_requested == 0;
|
|
}
|
|
|
|
} // namespace details
|
|
|
|
|
|
/*****
|
|
inspector<T> {
|
|
using type = T
|
|
// base_type is the base type inside c++ (e.g. std::vector<int> => int)
|
|
using base_type
|
|
// hdf5_type is the base read by hdf5 (c-type) (e.g. std::vector<std::string> => const char*)
|
|
using hdf5_type
|
|
|
|
// Is the inner type trivially copyable for optimisation
|
|
// If this value is true: data() is mandatory
|
|
// If this value is false: serialize, unserialize are mandatory
|
|
static constexpr bool is_trivially_copyable
|
|
|
|
// Is this type trivially nestable, i.e. is type[n] a contiguous
|
|
// array of `base_type[N]`?
|
|
static constexpr bool is_trivially_nestable
|
|
|
|
// Reading:
|
|
// Allocate the value following dims (should be recursive)
|
|
static void prepare(type& val, const std::vector<std::size_t> dims)
|
|
// Return a pointer of the first value of val (for reading)
|
|
static hdf5_type* data(type& val)
|
|
// Take a serialized vector 'in', some dims and copy value to val (for reading)
|
|
static void unserialize(const hdf5_type* in, const std::vector<size_t>&i, type& val)
|
|
|
|
|
|
// Writing:
|
|
// Return a point of the first value of val
|
|
static const hdf5_type* data(const type& val)
|
|
// Take a val and serialize it inside 'out'
|
|
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* out)
|
|
// Return an array of dimensions of the space needed for writing val
|
|
static std::vector<size_t> getDimensions(const type& val)
|
|
}
|
|
*****/
|
|
|
|
|
|
namespace details {
|
|
template <typename T>
|
|
struct type_helper {
|
|
using type = unqualified_t<T>;
|
|
using base_type = unqualified_t<T>;
|
|
using hdf5_type = base_type;
|
|
|
|
static constexpr size_t ndim = 0;
|
|
static constexpr size_t min_ndim = ndim;
|
|
static constexpr size_t max_ndim = ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<type>::value;
|
|
static constexpr bool is_trivially_nestable = is_trivially_copyable;
|
|
|
|
static size_t getRank(const type& /* val */) {
|
|
return ndim;
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& /* val */) {
|
|
return {};
|
|
}
|
|
|
|
static void prepare(type& /* val */, const std::vector<size_t>& /* dims */) {}
|
|
|
|
static hdf5_type* data(type& val) {
|
|
static_assert(is_trivially_copyable, "The type is not trivially copyable");
|
|
return &val;
|
|
}
|
|
|
|
static const hdf5_type* data(const type& val) {
|
|
static_assert(is_trivially_copyable, "The type is not trivially copyable");
|
|
return &val;
|
|
}
|
|
|
|
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
|
static_assert(is_trivially_copyable, "The type is not trivially copyable");
|
|
*m = val;
|
|
}
|
|
|
|
static void unserialize(const hdf5_type* vec,
|
|
const std::vector<size_t>& /* dims */,
|
|
type& val) {
|
|
static_assert(is_trivially_copyable, "The type is not trivially copyable");
|
|
val = vec[0];
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct inspector: type_helper<T> {};
|
|
|
|
enum class Boolean : int8_t {
|
|
HighFiveFalse = 0,
|
|
HighFiveTrue = 1,
|
|
};
|
|
|
|
template <>
|
|
struct inspector<bool>: type_helper<bool> {
|
|
using base_type = Boolean;
|
|
using hdf5_type = int8_t;
|
|
|
|
static constexpr bool is_trivially_copyable = false;
|
|
static constexpr bool is_trivially_nestable = false;
|
|
|
|
static hdf5_type* data(type& /* val */) {
|
|
throw DataSpaceException("A boolean cannot be read directly.");
|
|
}
|
|
|
|
static const hdf5_type* data(const type& /* val */) {
|
|
throw DataSpaceException("A boolean cannot be written directly.");
|
|
}
|
|
|
|
static void unserialize(const hdf5_type* vec,
|
|
const std::vector<size_t>& /* dims */,
|
|
type& val) {
|
|
val = vec[0] != 0;
|
|
}
|
|
|
|
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
|
*m = val ? 1 : 0;
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct inspector<std::string>: type_helper<std::string> {
|
|
using hdf5_type = const char*;
|
|
|
|
static hdf5_type* data(type& /* val */) {
|
|
throw DataSpaceException("A std::string cannot be read directly.");
|
|
}
|
|
|
|
static const hdf5_type* data(const type& /* val */) {
|
|
throw DataSpaceException("A std::string cannot be written directly.");
|
|
}
|
|
|
|
template <class It>
|
|
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, It m) {
|
|
(*m).assign(val.data(), val.size(), StringPadding::NullTerminated);
|
|
}
|
|
|
|
template <class It>
|
|
static void unserialize(const It& vec, const std::vector<size_t>& /* dims */, type& val) {
|
|
const auto& view = *vec;
|
|
val.assign(view.data(), view.length());
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct inspector<Reference>: type_helper<Reference> {
|
|
using hdf5_type = hobj_ref_t;
|
|
|
|
static constexpr bool is_trivially_copyable = false;
|
|
static constexpr bool is_trivially_nestable = false;
|
|
|
|
static hdf5_type* data(type& /* val */) {
|
|
throw DataSpaceException("A Reference cannot be read directly.");
|
|
}
|
|
|
|
static const hdf5_type* data(const type& /* val */) {
|
|
throw DataSpaceException("A Reference cannot be written directly.");
|
|
}
|
|
|
|
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
|
hobj_ref_t ref;
|
|
val.create_ref(&ref);
|
|
*m = ref;
|
|
}
|
|
|
|
static void unserialize(const hdf5_type* vec,
|
|
const std::vector<size_t>& /* dims */,
|
|
type& val) {
|
|
val = type{vec[0]};
|
|
}
|
|
};
|
|
|
|
template <typename T>
|
|
struct inspector<std::vector<T>> {
|
|
using type = std::vector<T>;
|
|
using value_type = unqualified_t<T>;
|
|
using base_type = typename inspector<value_type>::base_type;
|
|
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
|
|
|
static constexpr size_t ndim = 1;
|
|
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
|
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
|
inspector<value_type>::is_trivially_nestable;
|
|
static constexpr bool is_trivially_nestable = false;
|
|
|
|
static size_t getRank(const type& val) {
|
|
if (!val.empty()) {
|
|
return ndim + inspector<value_type>::getRank(val[0]);
|
|
} else {
|
|
return min_ndim;
|
|
}
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& val) {
|
|
auto rank = getRank(val);
|
|
std::vector<size_t> sizes(rank, 1ul);
|
|
sizes[0] = val.size();
|
|
if (!val.empty()) {
|
|
auto s = inspector<value_type>::getDimensions(val[0]);
|
|
for (size_t i = 0; i < s.size(); ++i) {
|
|
sizes[i + ndim] = s[i];
|
|
}
|
|
}
|
|
return sizes;
|
|
}
|
|
|
|
static void prepare(type& val, const std::vector<size_t>& dims) {
|
|
val.resize(dims[0]);
|
|
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
|
for (auto&& e: val) {
|
|
inspector<value_type>::prepare(e, next_dims);
|
|
}
|
|
}
|
|
|
|
static hdf5_type* data(type& val) {
|
|
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
static const hdf5_type* data(const type& val) {
|
|
return val.empty() ? nullptr : inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
template <class It>
|
|
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
|
if (!val.empty()) {
|
|
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
|
size_t subsize = compute_total_size(subdims);
|
|
for (auto&& e: val) {
|
|
inspector<value_type>::serialize(e, subdims, m);
|
|
m += subsize;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class It>
|
|
static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
|
|
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
|
size_t next_size = compute_total_size(next_dims);
|
|
for (size_t i = 0; i < dims[0]; ++i) {
|
|
inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct inspector<std::vector<bool>> {
|
|
using type = std::vector<bool>;
|
|
using value_type = bool;
|
|
using base_type = Boolean;
|
|
using hdf5_type = uint8_t;
|
|
|
|
static constexpr size_t ndim = 1;
|
|
static constexpr size_t min_ndim = ndim;
|
|
static constexpr size_t max_ndim = ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = false;
|
|
static constexpr bool is_trivially_nestable = false;
|
|
|
|
static size_t getRank(const type& /* val */) {
|
|
return ndim;
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& val) {
|
|
std::vector<size_t> sizes{val.size()};
|
|
return sizes;
|
|
}
|
|
|
|
static void prepare(type& val, const std::vector<size_t>& dims) {
|
|
if (dims.size() > 1) {
|
|
throw DataSpaceException("std::vector<bool> is only 1 dimension.");
|
|
}
|
|
val.resize(dims[0]);
|
|
}
|
|
|
|
static hdf5_type* data(type& /* val */) {
|
|
throw DataSpaceException("A std::vector<bool> cannot be read directly.");
|
|
}
|
|
|
|
static const hdf5_type* data(const type& /* val */) {
|
|
throw DataSpaceException("A std::vector<bool> cannot be written directly.");
|
|
}
|
|
|
|
static void serialize(const type& val, const std::vector<size_t>& /* dims*/, hdf5_type* m) {
|
|
for (size_t i = 0; i < val.size(); ++i) {
|
|
m[i] = val[i] ? 1 : 0;
|
|
}
|
|
}
|
|
|
|
static void unserialize(const hdf5_type* vec_align,
|
|
const std::vector<size_t>& dims,
|
|
type& val) {
|
|
for (size_t i = 0; i < dims[0]; ++i) {
|
|
val[i] = vec_align[i] != 0;
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename T, size_t N>
|
|
struct inspector<std::array<T, N>> {
|
|
using type = std::array<T, N>;
|
|
using value_type = unqualified_t<T>;
|
|
using base_type = typename inspector<value_type>::base_type;
|
|
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
|
|
|
static constexpr size_t ndim = 1;
|
|
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
|
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
|
inspector<value_type>::is_trivially_nestable;
|
|
static constexpr bool is_trivially_nestable = (sizeof(type) == N * sizeof(T)) &&
|
|
is_trivially_copyable;
|
|
|
|
static size_t getRank(const type& val) {
|
|
return ndim + inspector<value_type>::getRank(val[0]);
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& val) {
|
|
std::vector<size_t> sizes{N};
|
|
auto s = inspector<value_type>::getDimensions(val[0]);
|
|
sizes.insert(sizes.end(), s.begin(), s.end());
|
|
return sizes;
|
|
}
|
|
|
|
static void prepare(type& val, const std::vector<size_t>& dims) {
|
|
if (dims[0] > N) {
|
|
std::ostringstream os;
|
|
os << "Size of std::array (" << N << ") is too small for dims (" << dims[0] << ").";
|
|
throw DataSpaceException(os.str());
|
|
}
|
|
|
|
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
|
for (auto&& e: val) {
|
|
inspector<value_type>::prepare(e, next_dims);
|
|
}
|
|
}
|
|
|
|
static hdf5_type* data(type& val) {
|
|
return inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
static const hdf5_type* data(const type& val) {
|
|
return inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
template <class It>
|
|
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
|
|
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
|
size_t subsize = compute_total_size(subdims);
|
|
for (auto& e: val) {
|
|
inspector<value_type>::serialize(e, subdims, m);
|
|
m += subsize;
|
|
}
|
|
}
|
|
|
|
template <class It>
|
|
static void unserialize(const It& vec_align, const std::vector<size_t>& dims, type& val) {
|
|
if (dims[0] != N) {
|
|
std::ostringstream os;
|
|
os << "Impossible to pair DataSet with " << dims[0] << " elements into an array with "
|
|
<< N << " elements.";
|
|
throw DataSpaceException(os.str());
|
|
}
|
|
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
|
size_t next_size = compute_total_size(next_dims);
|
|
for (size_t i = 0; i < val.size(); ++i) {
|
|
inspector<value_type>::unserialize(vec_align + i * next_size, next_dims, val[i]);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
// Cannot be use for reading
|
|
template <typename T>
|
|
struct inspector<T*> {
|
|
using type = T*;
|
|
using value_type = unqualified_t<T>;
|
|
using base_type = typename inspector<value_type>::base_type;
|
|
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
|
|
|
static constexpr size_t ndim = 1;
|
|
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
|
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
|
inspector<value_type>::is_trivially_nestable;
|
|
static constexpr bool is_trivially_nestable = false;
|
|
|
|
static size_t getRank(const type& val) {
|
|
if (val != nullptr) {
|
|
return ndim + inspector<value_type>::getRank(val[0]);
|
|
} else {
|
|
return min_ndim;
|
|
}
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& /* val */) {
|
|
throw DataSpaceException("Not possible to have size of a T*");
|
|
}
|
|
|
|
static const hdf5_type* data(const type& val) {
|
|
return reinterpret_cast<const hdf5_type*>(val);
|
|
}
|
|
|
|
/* it works because there is only T[][][] currently
|
|
we will fix it one day */
|
|
static void serialize(const type& /* val */,
|
|
const std::vector<size_t>& /* dims*/,
|
|
hdf5_type* /* m */) {
|
|
throw DataSpaceException("Not possible to serialize a T*");
|
|
}
|
|
};
|
|
|
|
// Cannot be use for reading
|
|
template <typename T, size_t N>
|
|
struct inspector<T[N]> {
|
|
using type = T[N];
|
|
using value_type = unqualified_t<T>;
|
|
using base_type = typename inspector<value_type>::base_type;
|
|
using hdf5_type = typename inspector<value_type>::hdf5_type;
|
|
|
|
static constexpr size_t ndim = 1;
|
|
static constexpr size_t min_ndim = ndim + inspector<value_type>::min_ndim;
|
|
static constexpr size_t max_ndim = ndim + inspector<value_type>::max_ndim;
|
|
|
|
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
|
|
inspector<value_type>::is_trivially_nestable;
|
|
static constexpr bool is_trivially_nestable = is_trivially_copyable;
|
|
|
|
static void prepare(type& val, const std::vector<size_t>& dims) {
|
|
if (dims.empty()) {
|
|
throw DataSpaceException("Invalid 'dims', must be at least 1 dimensional.");
|
|
}
|
|
|
|
if (dims[0] != N) {
|
|
throw DataSpaceException("Dimensions mismatch.");
|
|
}
|
|
|
|
std::vector<size_t> next_dims(dims.begin() + 1, dims.end());
|
|
for (size_t i = 0; i < N; ++i) {
|
|
inspector<value_type>::prepare(val[i], next_dims);
|
|
}
|
|
}
|
|
|
|
static size_t getRank(const type& val) {
|
|
return ndim + inspector<value_type>::getRank(val[0]);
|
|
}
|
|
|
|
static std::vector<size_t> getDimensions(const type& val) {
|
|
std::vector<size_t> sizes{N};
|
|
auto s = inspector<value_type>::getDimensions(val[0]);
|
|
sizes.insert(sizes.end(), s.begin(), s.end());
|
|
return sizes;
|
|
}
|
|
|
|
static const hdf5_type* data(const type& val) {
|
|
return inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
static hdf5_type* data(type& val) {
|
|
return inspector<value_type>::data(val[0]);
|
|
}
|
|
|
|
/* it works because there is only T[][][] currently
|
|
we will fix it one day */
|
|
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
|
|
auto subdims = std::vector<size_t>(dims.begin() + 1, dims.end());
|
|
size_t subsize = compute_total_size(subdims);
|
|
for (size_t i = 0; i < N; ++i) {
|
|
inspector<value_type>::serialize(val[i], subdims, m + i * subsize);
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
} // namespace details
|
|
} // namespace HighFive
|