Skip to content

Commit

Permalink
Re-implement Eigen support.
Browse files Browse the repository at this point in the history
This commit adds support for Eigen matrices, arrays and maps.
  • Loading branch information
1uc committed Feb 19, 2024
1 parent fc74da7 commit 97d7120
Show file tree
Hide file tree
Showing 5 changed files with 375 additions and 42 deletions.
121 changes: 96 additions & 25 deletions include/highfive/eigen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,30 @@
namespace HighFive {
namespace details {

template <typename T, int M, int N>
struct inspector<Eigen::Matrix<T, M, N>> {
using type = Eigen::Matrix<T, M, N>;
using value_type = T;
template <class EigenType>
struct eigen_inspector {
using type = EigenType;
using value_type = typename EigenType::Scalar;
using base_type = typename inspector<value_type>::base_type;
using hdf5_type = base_type;

static_assert(int(EigenType::ColsAtCompileTime) == int(EigenType::MaxColsAtCompileTime),
"Padding isn't supported.");
static_assert(int(EigenType::RowsAtCompileTime) == int(EigenType::MaxRowsAtCompileTime),
"Padding isn't supported.");

static constexpr bool is_row_major() {
return EigenType::ColsAtCompileTime == 1 || EigenType::RowsAtCompileTime == 1 ||
EigenType::IsRowMajor;
}

static constexpr size_t ndim = 2;
static constexpr size_t recursive_ndim = ndim + inspector<value_type>::recursive_ndim;
static constexpr bool is_trivially_copyable = std::is_trivially_copyable<value_type>::value &&
static constexpr bool is_trivially_copyable = is_row_major() &&
std::is_trivially_copyable<value_type>::value &&
inspector<value_type>::is_trivially_copyable;


static void assert_not_buggy(Eigen::Index nrows, Eigen::Index ncols) {
if (nrows > 1 && ncols > 1) {
throw std::runtime_error(
"HighFive has been broken for Eigen::Matrix. Please check "
"https://github.com/BlueBrain/HighFive/issues/532.");
}
}

static std::vector<size_t> getDimensions(const type& val) {
assert_not_buggy(val.rows(), val.cols());

std::vector<size_t> sizes{static_cast<size_t>(val.rows()), static_cast<size_t>(val.cols())};
auto s = inspector<value_type>::getDimensions(val.data()[0]);
sizes.insert(sizes.end(), s.begin(), s.end());
Expand All @@ -45,38 +45,109 @@ struct inspector<Eigen::Matrix<T, M, N>> {
val.resize(static_cast<typename type::Index>(dims[0]),
static_cast<typename type::Index>(dims[1]));
}

assert_not_buggy(val.rows(), val.cols());
}

static hdf5_type* data(type& val) {
assert_not_buggy(val.rows(), val.cols());
if (!is_trivially_copyable) {
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
}

return inspector<value_type>::data(*val.data());
}

static const hdf5_type* data(const type& val) {
assert_not_buggy(val.rows(), val.cols());
if (!is_trivially_copyable) {
throw DataSetException("Invalid used of `inspector<Eigen::Matrix<...>>::data`.");
}

return inspector<value_type>::data(*val.data());
}

static void serialize(const type& val, const std::vector<size_t>& /* dims */, hdf5_type* m) {
assert_not_buggy(val.rows(), val.cols());
std::memcpy(m, val.data(), static_cast<size_t>(val.size()) * sizeof(hdf5_type));
static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
Eigen::Index n_rows = val.rows();
Eigen::Index n_cols = val.cols();

auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
auto subsize = compute_total_size(subdims);
for (Eigen::Index i = 0; i < n_rows; ++i) {
for (Eigen::Index j = 0; j < n_cols; ++j) {
inspector<value_type>::serialize(val(i, j), dims, m);
m += subsize;
}
}
}

static void unserialize(const hdf5_type* vec_align,
const std::vector<size_t>& dims,
type& val) {
assert_not_buggy(val.rows(), val.cols());
if (dims.size() < 2) {
std::ostringstream os;
os << "Impossible to pair DataSet with " << dims.size()
<< " dimensions into an eigen-matrix.";
throw DataSpaceException(os.str());
}
std::memcpy(val.data(), vec_align, compute_total_size(dims) * sizeof(hdf5_type));

auto n_rows = static_cast<Eigen::Index>(dims[0]);
auto n_cols = static_cast<Eigen::Index>(dims[1]);

auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
auto subsize = compute_total_size(subdims);
for (Eigen::Index i = 0; i < n_rows; ++i) {
for (Eigen::Index j = 0; j < n_cols; ++j) {
inspector<value_type>::unserialize(vec_align, subdims, val(i, j));
vec_align += subsize;
}
}
}
};

template <typename T, int M, int N, int Options>
struct inspector<Eigen::Matrix<T, M, N, Options>>
: public eigen_inspector<Eigen::Matrix<T, M, N, Options>> {
private:
using super = eigen_inspector<Eigen::Matrix<T, M, N, Options>>;

public:
using type = typename super::type;
using value_type = typename super::value_type;
using base_type = typename super::base_type;
using hdf5_type = typename super::hdf5_type;
};

template <typename T, int M, int N, int Options>
struct inspector<Eigen::Array<T, M, N, Options>>
: public eigen_inspector<Eigen::Array<T, M, N, Options>> {
private:
using super = eigen_inspector<Eigen::Array<T, M, N, Options>>;

public:
using type = typename super::type;
using value_type = typename super::value_type;
using base_type = typename super::base_type;
using hdf5_type = typename super::hdf5_type;
};


template <typename PlainObjectType, int MapOptions>
struct inspector<Eigen::Map<PlainObjectType, MapOptions>>
: public eigen_inspector<Eigen::Map<PlainObjectType, MapOptions>> {
private:
using super = eigen_inspector<Eigen::Map<PlainObjectType, MapOptions>>;

public:
using type = typename super::type;
using value_type = typename super::value_type;
using base_type = typename super::base_type;
using hdf5_type = typename super::hdf5_type;

static void prepare(type& val, const std::vector<size_t>& dims) {
if (dims[0] != static_cast<size_t>(val.rows()) ||
dims[1] != static_cast<size_t>(val.cols())) {
throw DataSetException("Eigen::Map has invalid shape and can't be resized.");
}
}
};


} // namespace details
} // namespace HighFive
Loading

0 comments on commit 97d7120

Please sign in to comment.