Add Dune::Std::submdspan
Summary
This merge request adds a standard-compatible Dune::Std::submdspan implementation for creating non-owning subviews of Dune::Std::mdspan.
The implementation follows the C++ standard library proposal and draft wording for std::submdspan:
- P2630R4:
submdspan - C++ working draft mdspan.sub
It intentionally does not add Dune-specific syntactic sugar or convenience wrappers. Additional helpers such as row(...), column(...), or Dune-specific range shorthands can be added later on top of this standard-shaped API.
Added API
The new public API is provided by dune/common/std/submdspan.hh.
It adds:
Dune::Std::full_extent_tDune::Std::full_extentDune::Std::extent_slice<Offset, Extent, Stride>Dune::Std::range_slice<First, Last, Stride = std::integral_constant<std::size_t,1>>Dune::Std::strided_slice, as compatibility spelling for an extent sliceDune::Std::subextents(...)Dune::Std::submdspan_mapping_result<Mapping>Dune::Std::submdspan_mapping(...)Dune::Std::submdspan(...)
The implementation is split into a small public header, a slice-specifier header, and an implementation header:
dune/common/std/submdspan.hhdune/common/std/submdspan_slices.hhdune/common/std/impl/submdspan.hh
Examples
Row and column views of a matrix
#include <array>
#include <dune/common/std/mdspan.hh>
#include <dune/common/std/submdspan.hh>
std::array<double, 12> data{};
Dune::Std::mdspan matrix(data.data(), 3, 4);
// Fix the first index: row 1, rank-1 view with extent 4.
auto row = Dune::Std::submdspan(
matrix,
1,
Dune::Std::full_extent);
// Fix the second index: column 2, rank-1 view with extent 3.
auto column = Dune::Std::submdspan(
matrix,
Dune::Std::full_extent,
2);
row(0) = 1.0;
column(1) = 2.0;Submatrix views
std::array<double, 20> data{};
Dune::Std::mdspan matrix(data.data(), 4, 5);
// Rows [1,3), columns [2,5).
auto block = Dune::Std::submdspan(
matrix,
Dune::Std::range_slice{1, 3},
Dune::Std::range_slice{2, 5});
// Every second column, starting at column 0, keeping two columns.
auto evenColumns = Dune::Std::submdspan(
matrix,
Dune::Std::full_extent,
Dune::Std::extent_slice{0, 2, 2});Std::mdarray to Std::mdspan
submdspan operates on mdspan. Owning mdarray objects can be sliced through their to_mdspan() view.
#include <dune/common/std/mdarray.hh>
#include <dune/common/std/submdspan.hh>
using Extents = Dune::Std::extents<int, 3, 4>;
using Storage = std::array<double, 12>;
Dune::Std::mdarray<double, Extents, Dune::Std::layout_right, Storage> values{};
auto span = values.to_mdspan();
auto row = Dune::Std::submdspan(span, 2, Dune::Std::full_extent);
row(1) = 3.14;Tensor slices
std::array<double, 2*3*4> data{};
Dune::Std::mdspan tensor(data.data(), 2, 3, 4);
// Fix the first tensor index and keep the trailing matrix.
auto face = Dune::Std::submdspan(
tensor,
1,
Dune::Std::full_extent,
Dune::Std::full_extent);
// Keep a range in the middle dimension and fix the last index.
auto strip = Dune::Std::submdspan(
tensor,
Dune::Std::full_extent,
Dune::Std::range_slice{1, 3},
2);Motivation and downstream use
One existing downstream use case is in dune-localfunctions, in the Lagrange simplex local basis implementation:
dune/localfunctions/lagrange/lagrangesimplex.hhThat code currently has a hand-written helper that fixes the first index of a layout_right multidimensional array. The comment already describes it as equivalent to:
std::submdspan(L, i, std::full_extent...)With this MR, the same intent can be expressed directly using the Dune backport:
auto Li = Dune::Std::submdspan(
L,
i,
Dune::Std::full_extent,
Dune::Std::full_extent);This keeps the indexing logic local to the mdspan utility and avoids reimplementing small slicing helpers in downstream modules.
Implementation notes
- Slice specifiers are modeled after the standard
std::submdspaninterface. - Integral slices fix an index and remove that rank from the result.
full_extentpreserves a dimension.range_sliceand pair-like ranges preserve a half-open index range.extent_slicesupports strided index sets.- The returned object is another
Dune::Std::mdspanaliasing the original data. - The implementation preserves
layout_rightfor fixed leading indices followed by full dimensions, andlayout_leftfor the symmetric fixed trailing-index case. - Other regular slices use
layout_stride.
Tests
The MR adds dune/common/std/test/submdspantest.cc.
The test covers:
- Row slices of
layout_rightmdspans - Column slices of
layout_leftmdspans - Scalar rank-0 slices
- Const element propagation
- Range and strided slices
- Pair-like range slices
subextents(...)- Slicing a
Std::mdarrayviato_mdspan() - A LagrangeSimplex-style fixed-first-index slice
The related existing tests for mdspan, mdarray, and layout mappings continue to pass.