From 2b59cd25ff9fd52f82eeb1ef21ccf4e7222a3a97 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 10 Jul 2024 10:18:38 +0200 Subject: [PATCH 1/2] Refactor inspector for std::span. --- .../highfive/bits/inspector_stl_span_misc.hpp | 98 +++++++++++++++++++ include/highfive/span.hpp | 89 ++--------------- 2 files changed, 108 insertions(+), 79 deletions(-) create mode 100644 include/highfive/bits/inspector_stl_span_misc.hpp diff --git a/include/highfive/bits/inspector_stl_span_misc.hpp b/include/highfive/bits/inspector_stl_span_misc.hpp new file mode 100644 index 000000000..226be4dc0 --- /dev/null +++ b/include/highfive/bits/inspector_stl_span_misc.hpp @@ -0,0 +1,98 @@ +#pragma once + +#include "H5Inspector_decl.hpp" +#include "../H5Exception.hpp" + +#include +#include +#include + +namespace HighFive { +namespace details { + + +// Anything with the same API as `std::span` can implemented by inheriting from +// this class. +template +struct inspector_stl_span { + using type = Span; + using value_type = unqualified_t; + using base_type = typename inspector::base_type; + using hdf5_type = typename inspector::hdf5_type; + + static constexpr size_t ndim = 1; + static constexpr size_t min_ndim = ndim + inspector::min_ndim; + static constexpr size_t max_ndim = ndim + inspector::max_ndim; + + static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && + inspector::is_trivially_nestable; + static constexpr bool is_trivially_nestable = false; + + + static size_t getRank(const type& val) { + if (!val.empty()) { + return ndim + inspector::getRank(val[0]); + } else { + return min_ndim; + } + } + + static std::vector getDimensions(const type& val) { + auto rank = getRank(val); + std::vector sizes(rank, 1ul); + sizes[0] = val.size(); + if (!val.empty()) { + auto s = inspector::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& 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::data(val[0]); + } + + static const hdf5_type* data(const type& val) { + return val.empty() ? nullptr : inspector::data(val[0]); + } + + template + static void serialize(const type& val, const std::vector& dims, It m) { + if (!val.empty()) { + auto subdims = std::vector(dims.begin() + ndim, dims.end()); + size_t subsize = compute_total_size(subdims); + for (const auto& e: val) { + inspector::serialize(e, subdims, m); + m += subsize; + } + } + } + + template + static void unserialize(const It& vec_align, const std::vector& dims, type& val) { + std::vector subdims(dims.begin() + ndim, dims.end()); + size_t subsize = compute_total_size(subdims); + for (size_t i = 0; i < dims[0]; ++i) { + inspector::unserialize(vec_align + i * subsize, subdims, val[i]); + } + } +}; + +} // namespace details +} // namespace HighFive diff --git a/include/highfive/span.hpp b/include/highfive/span.hpp index ab53319ee..eb0dd1571 100644 --- a/include/highfive/span.hpp +++ b/include/highfive/span.hpp @@ -10,7 +10,7 @@ #pragma once #include "bits/H5Inspector_decl.hpp" -#include "H5Exception.hpp" +#include "bits/inspector_stl_span_misc.hpp" #include @@ -18,84 +18,15 @@ namespace HighFive { namespace details { template -struct inspector> { - using type = std::span; - using value_type = unqualified_t; - using base_type = typename inspector::base_type; - using hdf5_type = typename inspector::hdf5_type; - - static constexpr size_t ndim = 1; - static constexpr size_t min_ndim = ndim + inspector::min_ndim; - static constexpr size_t max_ndim = ndim + inspector::max_ndim; - - static constexpr bool is_trivially_copyable = std::is_trivially_copyable::value && - inspector::is_trivially_nestable; - static constexpr bool is_trivially_nestable = false; - - - static size_t getRank(const type& val) { - if (!val.empty()) { - return ndim + inspector::getRank(val[0]); - } else { - return min_ndim; - } - } - - static std::vector getDimensions(const type& val) { - auto rank = getRank(val); - std::vector sizes(rank, 1ul); - sizes[0] = val.size(); - if (!val.empty()) { - auto s = inspector::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& 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::data(val[0]); - } - - static const hdf5_type* data(const type& val) { - return val.empty() ? nullptr : inspector::data(val[0]); - } - - template - static void serialize(const type& val, const std::vector& dims, It m) { - if (!val.empty()) { - auto subdims = std::vector(dims.begin() + ndim, dims.end()); - size_t subsize = compute_total_size(subdims); - for (const auto& e: val) { - inspector::serialize(e, subdims, m); - m += subsize; - } - } - } - - template - static void unserialize(const It& vec_align, const std::vector& dims, type& val) { - std::vector subdims(dims.begin() + ndim, dims.end()); - size_t subsize = compute_total_size(subdims); - for (size_t i = 0; i < dims[0]; ++i) { - inspector::unserialize(vec_align + i * subsize, subdims, val[i]); - } - } +struct inspector>: public inspector_stl_span> { + private: + using super = inspector_stl_span>; + + 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 From 175f13d48a16221c87c57562843634a3f4c2b177 Mon Sep 17 00:00:00 2001 From: Luc Grosheintz Date: Wed, 10 Jul 2024 11:06:23 +0200 Subject: [PATCH 2/2] Implement `boost::span`. --- include/highfive/boost.hpp | 14 +++++++++++ tests/unit/data_generator.hpp | 43 ++++++++++++++++++++++++++++------ tests/unit/supported_types.hpp | 10 ++++++++ 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/include/highfive/boost.hpp b/include/highfive/boost.hpp index 33c1458df..6937376b9 100644 --- a/include/highfive/boost.hpp +++ b/include/highfive/boost.hpp @@ -2,9 +2,11 @@ #include "bits/H5Inspector_decl.hpp" #include "H5Exception.hpp" +#include "bits/inspector_stl_span_misc.hpp" #include #include +#include namespace HighFive { namespace details { @@ -172,5 +174,17 @@ struct inspector> { } }; +template +struct inspector>: public inspector_stl_span> { + private: + using super = inspector_stl_span>; + + 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 diff --git a/tests/unit/data_generator.hpp b/tests/unit/data_generator.hpp index e4e7dfa85..4f0c31e8f 100644 --- a/tests/unit/data_generator.hpp +++ b/tests/unit/data_generator.hpp @@ -236,12 +236,15 @@ struct ContainerTraits>: public STLLikeContainerTraits -struct ContainerTraits>: public STLLikeContainerTraits> { +// 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 +struct STLSpanLikeContainerTraits: public STLLikeContainerTraits { private: - using super = STLLikeContainerTraits>; + using super = STLLikeContainerTraits; public: using container_type = typename super::container_type; @@ -274,12 +277,26 @@ struct ContainerTraits>: public STLLikeContainerTraits& dims, size_t axis) { - if (Extent != std::dynamic_extent) { - dims[axis] = Extent; + if (Span::extent != DynamicExtent) { + dims[axis] = Span::extent; ContainerTraits::sanitize_dims(dims, axis + 1); } } }; + + +#ifdef HIGHFIVE_TEST_SPAN +template +struct ContainerTraits> + : public STLSpanLikeContainerTraits, std::dynamic_extent> { + private: + using super = STLSpanLikeContainerTraits, 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 @@ -426,6 +443,18 @@ struct ContainerTraits> { } }; +template +struct ContainerTraits> + : public STLSpanLikeContainerTraits, boost::dynamic_extent> { + private: + using super = STLSpanLikeContainerTraits, 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 ------------------------------------------------------------------- diff --git a/tests/unit/supported_types.hpp b/tests/unit/supported_types.hpp index 5f1bf6453..45473630e 100644 --- a/tests/unit/supported_types.hpp +++ b/tests/unit/supported_types.hpp @@ -54,6 +54,12 @@ struct BoostUblasMatrix { template using type = boost::numeric::ublas::matrix>; }; + +template +struct BoostSpan { + template + using type = boost::span>; +}; #endif #ifdef HIGHFIVE_TEST_EIGEN @@ -152,6 +158,10 @@ using supported_array_types = typename ConcatenateTuples< typename ContainerProduct, scalar_types_boost>::type, typename ContainerProduct>, scalar_types_boost>::type, typename ContainerProduct>, scalar_types_boost>::type, + + typename ContainerProduct, scalar_types_boost>::type, + typename ContainerProduct>, scalar_types_boost>::type, + typename ContainerProduct>, scalar_types_boost>::type, #endif #ifdef HIGHFIVE_TEST_EIGEN typename ContainerProduct, scalar_types_eigen>::type,