Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement boost::span. #1025

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions include/highfive/bits/inspector_stl_span_misc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#pragma once

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

#include <cstdlib>
#include <vector>
#include <type_traits>

namespace HighFive {
namespace details {


// Anything with the same API as `std::span` can implemented by inheriting from
// this class.
template <class Span>
struct inspector_stl_span {
using type = Span;
using value_type = unqualified_t<typename Span::value_type>;
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]);
assert(s.size() + ndim == sizes.size());
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>& expected_dims) {
auto actual_dims = getDimensions(val);
if (actual_dims.size() != expected_dims.size()) {
throw DataSpaceException("Mismatching rank.");
}

for (size_t i = 0; i < actual_dims.size(); ++i) {
if (actual_dims[i] != expected_dims[i]) {
throw DataSpaceException("Mismatching dimensions.");
}
}
}

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() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (const 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> subdims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < dims[0]; ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize, subdims, val[i]);
}
}
};

} // namespace details
} // namespace HighFive
14 changes: 14 additions & 0 deletions include/highfive/boost.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

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

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

namespace HighFive {
namespace details {
Expand Down Expand Up @@ -172,5 +174,17 @@ struct inspector<boost::numeric::ublas::matrix<T>> {
}
};

template <class T, std::size_t Extent>
struct inspector<boost::span<T, Extent>>: public inspector_stl_span<boost::span<T, Extent>> {
private:
using super = inspector_stl_span<boost::span<T, Extent>>;

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;
};

} // namespace details
} // namespace HighFive
89 changes: 10 additions & 79 deletions include/highfive/span.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,92 +10,23 @@
#pragma once

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

#include <span>

namespace HighFive {
namespace details {

template <class T, std::size_t Extent>
struct inspector<std::span<T, Extent>> {
using type = std::span<T, Extent>;
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]);
assert(s.size() + ndim == sizes.size());
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>& expected_dims) {
auto actual_dims = getDimensions(val);
if (actual_dims.size() != expected_dims.size()) {
throw DataSpaceException("Mismatching rank.");
}

for (size_t i = 0; i < actual_dims.size(); ++i) {
if (actual_dims[i] != expected_dims[i]) {
throw DataSpaceException("Mismatching dimensions.");
}
}
}

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() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (const 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> subdims(dims.begin() + ndim, dims.end());
size_t subsize = compute_total_size(subdims);
for (size_t i = 0; i < dims[0]; ++i) {
inspector<value_type>::unserialize(vec_align + i * subsize, subdims, val[i]);
}
}
struct inspector<std::span<T, Extent>>: public inspector_stl_span<std::span<T, Extent>> {
private:
using super = inspector_stl_span<std::span<T, Extent>>;

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;
};

} // namespace details
Expand Down
43 changes: 36 additions & 7 deletions tests/unit/data_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,15 @@ struct ContainerTraits<std::array<T, N>>: public STLLikeContainerTraits<std::arr
}
};


#ifdef HIGHFIVE_TEST_SPAN
template <class T, std::size_t Extent>
struct ContainerTraits<std::span<T, Extent>>: public STLLikeContainerTraits<std::span<T, Extent>> {
// Anything with the same API as `std::span` can implemented by inheriting from
// this class.
//
// The template parameter `DynamicExtent` is the equivalent of the magic number
// `std::dynamic_extent`.
template <class Span, size_t DynamicExtent>
struct STLSpanLikeContainerTraits: public STLLikeContainerTraits<Span> {
private:
using super = STLLikeContainerTraits<std::span<T, Extent>>;
using super = STLLikeContainerTraits<Span>;

public:
using container_type = typename super::container_type;
Expand Down Expand Up @@ -274,12 +277,26 @@ struct ContainerTraits<std::span<T, Extent>>: public STLLikeContainerTraits<std:
}

static void sanitize_dims(std::vector<size_t>& dims, size_t axis) {
if (Extent != std::dynamic_extent) {
dims[axis] = Extent;
if (Span::extent != DynamicExtent) {
dims[axis] = Span::extent;
ContainerTraits<value_type>::sanitize_dims(dims, axis + 1);
}
}
};


#ifdef HIGHFIVE_TEST_SPAN
template <class T, std::size_t Extent>
struct ContainerTraits<std::span<T, Extent>>
: public STLSpanLikeContainerTraits<std::span<T, Extent>, std::dynamic_extent> {
private:
using super = STLSpanLikeContainerTraits<std::span<T, Extent>, std::dynamic_extent>;

public:
using container_type = typename super::container_type;
using value_type = typename super::value_type;
using base_type = typename super::base_type;
};
#endif


Expand Down Expand Up @@ -426,6 +443,18 @@ struct ContainerTraits<boost::numeric::ublas::matrix<T>> {
}
};

template <class T, std::size_t Extent>
struct ContainerTraits<boost::span<T, Extent>>
: public STLSpanLikeContainerTraits<boost::span<T, Extent>, boost::dynamic_extent> {
private:
using super = STLSpanLikeContainerTraits<boost::span<T, Extent>, boost::dynamic_extent>;

public:
using container_type = typename super::container_type;
using value_type = typename super::value_type;
using base_type = typename super::base_type;
};

#endif

// -- Eigen -------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/supported_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ struct BoostUblasMatrix {
template <class T>
using type = boost::numeric::ublas::matrix<typename C::template type<T>>;
};

template <class C = type_identity>
struct BoostSpan {
template <class T>
using type = boost::span<typename C::template type<T>>;
};
#endif

#ifdef HIGHFIVE_TEST_EIGEN
Expand Down Expand Up @@ -152,6 +158,10 @@ using supported_array_types = typename ConcatenateTuples<
typename ContainerProduct<BoostUblasMatrix<>, scalar_types_boost>::type,
typename ContainerProduct<STDVector<BoostUblasMatrix<>>, scalar_types_boost>::type,
typename ContainerProduct<STDArray<5, BoostUblasMatrix<>>, scalar_types_boost>::type,

typename ContainerProduct<BoostSpan<>, scalar_types_boost>::type,
typename ContainerProduct<STDVector<BoostSpan<>>, scalar_types_boost>::type,
typename ContainerProduct<STDArray<5, BoostSpan<>>, scalar_types_boost>::type,
#endif
#ifdef HIGHFIVE_TEST_EIGEN
typename ContainerProduct<EigenMatrix<3, 5, Eigen::ColMajor>, scalar_types_eigen>::type,
Expand Down
Loading