Add implementation of span, mdspan and mdarray
Summary
This MR provides a reference implementation of std::span
, std::mdspan
, and std::mdarray
including all its utilities, std::dynamic_extent
, std::extents
, std::layout_[left|right|stride]
, and std::default_accessor
, plus a few backports of c++20 standard library functions, e.g. std::to_address
. All these entities are put into the Dune::Std
namespace including an import of the actual standard implementation if available.
Motivation
In Dune we do not have tensor data structures. The containers and views provided in this MR can be the basis for such an implementation. A reference code is available in https://gitlab.dune-project.org/simon.praetorius/dune-tensor. Also, these types could be the start of a reimplementation of DenseVector
and DenseMatrix
and all their derived types.
Deprecation
While posting these implementations here, they are meant to be deprecated once the standard libraries we support in Dune all ship their implementation of these classes. Currently, it is only the most recent version, clang-18, with its libc++ that supports at least std::mdspan
. In the module dune-tensor there are already CI jobs testing with this compiler and this library. Other classes, like std::span
or the utility std::to_address
might be deprecated more early, once we support only c++20 compatible compilers. The implementation in this MR is (mostly) c++17 compatible.
Provided classes
Dune::Std::span
A contiguous sequence of elements with static or dynamic extent. The implementation is based on the C++ standard working draft https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf and the documentation provided in https://en.cppreference.com/w/cpp/container/span.
Example
std::vector v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// view data as contiguous memory representing 10 elements
auto s1 = Dune::Std::span(v.data(), 10);
// view data as contiguous memory with static size
auto s2 = Dune::Std::span<int,10>(v.data());
// write data using 2D view
for (std::size_t i = 0; i != s1.size(); i++)
s1[i] = 2*i;
Not that dynamic extents are specified by the constant Dune::Std::dynamic_extent
.
Dune::Std::mdspan
A multi-dimensional non-owning array view. The implementation is based in the standard proposal https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r17.html and the C++ standard working draft https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4971.pdf.
Example
std::vector v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
// view data as contiguous memory representing 2 rows and 5 columns
// with row-major ordering.
auto ms = Dune::Std::mdspan(v.data(), 2, 5);
// or with static shape given by Std::extents
auto ms2 = Dune::Std::mdspan<int,Dune::Std::extents<int,2,5>>(v.data());
// write data using 2D view
for (std::size_t i = 0; i != ms.extent(0); i++)
for (std::size_t j = 0; j != ms.extent(1); j++)
ms(i, j) = i + j; // or ms[i, j]
Dune::Std::mdarray
An owning multi-dimensional array analog of mdspan. The implementation is inspired by the mdarray c++ standard proposals https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p1684r5.html.
Example
// two-dimensional array with 2 rows and 6 columns of static shape
Dune::Std::mdarray<double, Dune::Std::extents<std::size_t,2,6>> m1{};
// same two-dimensional array but with dynamic shape
Dune::Std::mdarray<double, Dune::Std::dextents<std::size_t,2>> m2{2,6};
// storage type similar to the Dune::FieldMatrix
template <class T, int m, int n>
using FieldMatrix = Dune::Std::mdarray<T,
Dune::Std::extents<int,m,n>, Dune::Std::layout_right, std::array<T,m*n>>;
// store data into the array using two indices
for (std::size_t i = 0; i != m1.extent(0); i++)
for (std::size_t j = 0; j != m1.extent(1); j++)
m1(i, j) = i + j; // or m1[i, j]
Note that std::mdarray
is not yet fully standardized, but hopefully will be in c++26. There is also no other reference implementation following the recent proposal. The Kokkos implementation (in the current stable
branch) still follows the proposal version R4.