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:

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_t
  • Dune::Std::full_extent
  • Dune::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 slice
  • Dune::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.hh
  • dune/common/std/submdspan_slices.hh
  • dune/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.hh

That 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::submdspan interface.
  • Integral slices fix an index and remove that rank from the result.
  • full_extent preserves a dimension.
  • range_slice and pair-like ranges preserve a half-open index range.
  • extent_slice supports strided index sets.
  • The returned object is another Dune::Std::mdspan aliasing the original data.
  • The implementation preserves layout_right for fixed leading indices followed by full dimensions, and layout_left for 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_right mdspans
  • Column slices of layout_left mdspans
  • Scalar rank-0 slices
  • Const element propagation
  • Range and strided slices
  • Pair-like range slices
  • subextents(...)
  • Slicing a Std::mdarray via to_mdspan()
  • A LagrangeSimplex-style fixed-first-index slice

The related existing tests for mdspan, mdarray, and layout mappings continue to pass.

Edited by Simon Praetorius

Merge request reports

Loading