Skip to content

Commit

Permalink
Split highfive/boost.hpp. (#1067)
Browse files Browse the repository at this point in the history
Allowing more precise control over which parts of
boost need to be available.
  • Loading branch information
1uc authored Dec 2, 2024
1 parent c890ad4 commit 479bfbd
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 175 deletions.
176 changes: 2 additions & 174 deletions include/highfive/boost.hpp
Original file line number Diff line number Diff line change
@@ -1,176 +1,4 @@
#pragma once

#include "bits/H5Inspector_decl.hpp"
#include "H5Exception.hpp"

#include <boost/multi_array.hpp>
#include <boost/numeric/ublas/matrix.hpp>

namespace HighFive {
namespace details {

template <typename T, size_t Dims>
struct inspector<boost::multi_array<T, Dims>> {
using type = boost::multi_array<T, Dims>;
using value_type = T;
using base_type = typename inspector<value_type>::base_type;
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = Dims;
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) {
return ndim + inspector<value_type>::getRank(val.data()[0]);
}

static std::vector<size_t> getDimensions(const type& val) {
auto rank = getRank(val);
std::vector<size_t> sizes(rank, 1ul);
for (size_t i = 0; i < ndim; ++i) {
sizes[i] = val.shape()[i];
}
if (val.size() != 0) {
auto s = inspector<value_type>::getDimensions(val.data()[0]);
sizes.resize(ndim + s.size());
for (size_t i = 0; i < s.size(); ++i) {
sizes[ndim + i] = s[i];
}
}
return sizes;
}

static void prepare(type& val, const std::vector<size_t>& dims) {
if (dims.size() < ndim) {
std::ostringstream os;
os << "Only '" << dims.size() << "' given but boost::multi_array is of size '" << ndim
<< "'.";
throw DataSpaceException(os.str());
}
boost::array<typename type::index, Dims> ext;
std::copy(dims.begin(), dims.begin() + ndim, ext.begin());
val.resize(ext);
std::vector<size_t> next_dims(dims.begin() + Dims, dims.end());
std::size_t size = std::accumulate(dims.begin(),
dims.begin() + Dims,
std::size_t{1},
std::multiplies<size_t>());
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::prepare(*(val.origin() + i), next_dims);
}
}

static void assert_c_order(const type& val) {
if (!(val.storage_order() == boost::c_storage_order())) {
throw DataTypeException("Only C storage order is supported for 'boost::multi_array'.");
}
}

static hdf5_type* data(type& val) {
assert_c_order(val);
return inspector<value_type>::data(*val.data());
}

static const hdf5_type* data(const type& val) {
assert_c_order(val);
return inspector<value_type>::data(*val.data());
}

template <class It>
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
assert_c_order(val);
size_t size = val.num_elements();
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::serialize(*(val.origin() + i), subdims, m + i * subsize);
}
}

template <class It>
static void unserialize(It vec_align, const std::vector<size_t>& dims, type& val) {
assert_c_order(val);
std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(next_dims);
for (size_t i = 0; i < val.num_elements(); ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize,
next_dims,
*(val.origin() + i));
}
}
};

template <typename T>
struct inspector<boost::numeric::ublas::matrix<T>> {
using type = boost::numeric::ublas::matrix<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 = 2;
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_copyable;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val(0, 0));
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{val.size1(), val.size2()};
auto s = inspector<value_type>::getDimensions(val(0, 0));
sizes.insert(sizes.end(), s.begin(), s.end());
return sizes;
}

static void prepare(type& val, const std::vector<size_t>& dims) {
if (dims.size() < ndim) {
std::ostringstream os;
os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim
<< " boost::numeric::ublas::matrix";
throw DataSpaceException(os.str());
}
val.resize(dims[0], dims[1], false);
}

static hdf5_type* data(type& val) {
return inspector<value_type>::data(val(0, 0));
}

static const hdf5_type* data(const type& val) {
return inspector<value_type>::data(val(0, 0));
}

static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
size_t size = val.size1() * val.size2();
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::serialize(*(&val(0, 0) + i), subdims, m + i * subsize);
}
}

static void unserialize(const hdf5_type* vec_align,
const std::vector<size_t>& dims,
type& val) {
std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(next_dims);
size_t size = val.size1() * val.size2();
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize,
next_dims,
*(&val(0, 0) + i));
}
}
};

} // namespace details
} // namespace HighFive
#include "boost_ublas.hpp"
#include "boost_multi_array.hpp"
108 changes: 108 additions & 0 deletions include/highfive/boost_multi_array.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#pragma once

#include "bits/H5Inspector_decl.hpp"
#include "H5Exception.hpp"

#include <boost/multi_array.hpp>

namespace HighFive {
namespace details {

template <typename T, size_t Dims>
struct inspector<boost::multi_array<T, Dims>> {
using type = boost::multi_array<T, Dims>;
using value_type = T;
using base_type = typename inspector<value_type>::base_type;
using hdf5_type = typename inspector<value_type>::hdf5_type;

static constexpr size_t ndim = Dims;
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) {
return ndim + inspector<value_type>::getRank(val.data()[0]);
}

static std::vector<size_t> getDimensions(const type& val) {
auto rank = getRank(val);
std::vector<size_t> sizes(rank, 1ul);
for (size_t i = 0; i < ndim; ++i) {
sizes[i] = val.shape()[i];
}
if (val.size() != 0) {
auto s = inspector<value_type>::getDimensions(val.data()[0]);
sizes.resize(ndim + s.size());
for (size_t i = 0; i < s.size(); ++i) {
sizes[ndim + i] = s[i];
}
}
return sizes;
}

static void prepare(type& val, const std::vector<size_t>& dims) {
if (dims.size() < ndim) {
std::ostringstream os;
os << "Only '" << dims.size() << "' given but boost::multi_array is of size '" << ndim
<< "'.";
throw DataSpaceException(os.str());
}
boost::array<typename type::index, Dims> ext;
std::copy(dims.begin(), dims.begin() + ndim, ext.begin());
val.resize(ext);
std::vector<size_t> next_dims(dims.begin() + Dims, dims.end());
std::size_t size = std::accumulate(dims.begin(),
dims.begin() + Dims,
std::size_t{1},
std::multiplies<size_t>());
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::prepare(*(val.origin() + i), next_dims);
}
}

static void assert_c_order(const type& val) {
if (!(val.storage_order() == boost::c_storage_order())) {
throw DataTypeException("Only C storage order is supported for 'boost::multi_array'.");
}
}

static hdf5_type* data(type& val) {
assert_c_order(val);
return inspector<value_type>::data(*val.data());
}

static const hdf5_type* data(const type& val) {
assert_c_order(val);
return inspector<value_type>::data(*val.data());
}

template <class It>
static void serialize(const type& val, const std::vector<size_t>& dims, It m) {
assert_c_order(val);
size_t size = val.num_elements();
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::serialize(*(val.origin() + i), subdims, m + i * subsize);
}
}

template <class It>
static void unserialize(It vec_align, const std::vector<size_t>& dims, type& val) {
assert_c_order(val);
std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(next_dims);
for (size_t i = 0; i < val.num_elements(); ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize,
next_dims,
*(val.origin() + i));
}
}
};

} // namespace details
} // namespace HighFive
79 changes: 79 additions & 0 deletions include/highfive/boost_ublas.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#pragma once

#include "bits/H5Inspector_decl.hpp"
#include "H5Exception.hpp"

#include <boost/numeric/ublas/matrix.hpp>

namespace HighFive {
namespace details {

template <typename T>
struct inspector<boost::numeric::ublas::matrix<T>> {
using type = boost::numeric::ublas::matrix<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 = 2;
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_copyable;
static constexpr bool is_trivially_nestable = false;

static size_t getRank(const type& val) {
return ndim + inspector<value_type>::getRank(val(0, 0));
}

static std::vector<size_t> getDimensions(const type& val) {
std::vector<size_t> sizes{val.size1(), val.size2()};
auto s = inspector<value_type>::getDimensions(val(0, 0));
sizes.insert(sizes.end(), s.begin(), s.end());
return sizes;
}

static void prepare(type& val, const std::vector<size_t>& dims) {
if (dims.size() < ndim) {
std::ostringstream os;
os << "Impossible to pair DataSet with " << dims.size() << " dimensions into a " << ndim
<< " boost::numeric::ublas::matrix";
throw DataSpaceException(os.str());
}
val.resize(dims[0], dims[1], false);
}

static hdf5_type* data(type& val) {
return inspector<value_type>::data(val(0, 0));
}

static const hdf5_type* data(const type& val) {
return inspector<value_type>::data(val(0, 0));
}

static void serialize(const type& val, const std::vector<size_t>& dims, hdf5_type* m) {
size_t size = val.size1() * val.size2();
auto subdims = std::vector<size_t>(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::serialize(*(&val(0, 0) + i), subdims, m + i * subsize);
}
}

static void unserialize(const hdf5_type* vec_align,
const std::vector<size_t>& dims,
type& val) {
std::vector<size_t> next_dims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(next_dims);
size_t size = val.size1() * val.size2();
for (size_t i = 0; i < size; ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize,
next_dims,
*(&val(0, 0) + i));
}
}
};

} // namespace details
} // namespace HighFive
2 changes: 1 addition & 1 deletion tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ foreach(PUBLIC_HEADER ${public_headers})
continue()
endif()

if(PUBLIC_HEADER STREQUAL "highfive/boost.hpp" AND NOT HIGHFIVE_TEST_BOOST)
if(PUBLIC_HEADER MATCHES "highfive/boost.*.hpp" AND NOT HIGHFIVE_TEST_BOOST)
continue()
endif()

Expand Down

0 comments on commit 479bfbd

Please sign in to comment.