Add Padded mdspan Layout Mappings

Summary

This merge request adds the standard padded layout mappings for the Dune::Std::mdspan backport:

  • Dune::Std::layout_left_padded<PaddingValue>
  • Dune::Std::layout_right_padded<PaddingValue>

The implementation follows the padded-layout proposal P2642R0 and the corresponding C++ working draft wording for mdspan layout mappings.

This MR only adds the padded layout mappings themselves. The related submdspan utility is handled separately in !1639. That follow-up is where these layouts become especially useful for returning specialized submatrix layouts instead of falling back to layout_stride.

Motivation

There are two main motivations.

First, padded layouts describe dense multidimensional storage where one dimension remains contiguous, but the stride to the next row or column is larger than the logical extent. This is common for pitched allocations, aligned rows, cache-friendly storage, and interoperability with libraries that use a leading dimension.

Second, P2642 explicitly motivates padded layouts as result layouts for submdspan. Consider a row-major matrix with logical extents (m,n) and a submatrix selecting only columns [j0,j1). Inside one row of the submatrix, consecutive column entries are still contiguous. But moving from the end of one submatrix row to the next source row must use the full row stride of the original matrix, not the smaller number of columns in the submatrix.

Mathematically, for a row-major matrix with source row stride S, a submatrix view maps

(i,j) -> base + i*S + j

where S is the original row stride. A plain layout_right mapping for the submatrix would use j1-j0 as the row stride and would therefore jump to the wrong memory position. layout_right_padded represents exactly this case: the rightmost dimension is contiguous, but the previous stride is explicitly supplied. The layout_left_padded case is symmetric for column-major storage.

The same idea is relevant for over-aligned storage and SIMD-friendly kernels. Padded layouts provide a standard mdspan way to express storage where rows, columns, or leading dimensions are rounded or chosen to satisfy alignment or vectorization requirements without changing the logical extents.

Added API

The new headers are:

  • dune/common/std/layout_left_padded.hh
  • dune/common/std/layout_right_padded.hh

Examples

Row-Major Padded Storage

#include <vector>

#include <dune/common/std/extents.hh>
#include <dune/common/std/layout_right_padded.hh>
#include <dune/common/std/mdspan.hh>

using Extents = Dune::Std::extents<int, 3, 5>;
using Layout = Dune::Std::layout_right_padded<8>;
using Mapping = Layout::mapping<Extents>;

Mapping mapping(Extents{});
std::vector<double> data(mapping.required_span_size());

Dune::Std::mdspan<double, Extents, Layout> a(data.data(), mapping);

// Logical row length is 5, but stride(0) is 8.
a(2,4) = 1.0;

Column-Major Padded Storage

#include <vector>

#include <dune/common/std/extents.hh>
#include <dune/common/std/layout_left_padded.hh>
#include <dune/common/std/mdspan.hh>

using Extents = Dune::Std::extents<int, 5, 3>;
using Layout = Dune::Std::layout_left_padded<8>;
using Mapping = Layout::mapping<Extents>;

Mapping mapping(Extents{});
std::vector<double> data(mapping.required_span_size());

Dune::Std::mdspan<double, Extents, Layout> a(data.data(), mapping);

// Logical column length is 5, but stride(1) is 8.
a(4,2) = 2.0;

Runtime Padding

#include <vector>

#include <dune/common/std/extents.hh>
#include <dune/common/std/layout_right_padded.hh>
#include <dune/common/std/mdspan.hh>

using Extents = Dune::Std::dextents<int, 2>;
using Layout = Dune::Std::layout_right_padded<>;
using Mapping = Layout::mapping<Extents>;

Extents extents{3, 5};
Mapping mapping(extents, 8); // runtime row stride

std::vector<double> data(mapping.required_span_size());
Dune::Std::mdspan<double, Extents, Layout> a(data.data(), mapping);

Relation To submdspan

This MR does not add submdspan. That is covered in !1639.

The connection is important, though: once submdspan is available, submatrix views can return a padded layout where possible. For example, a row-major submatrix that keeps a contiguous range of columns still needs the original full row stride. Such a view is more specific than layout_stride, and layout_right_padded can represent it directly. The layout_left_padded case is the corresponding column-major variant. A corresponding extension of the !1639 proposal is in preparation.

Implementation Notes

  • layout_right_padded keeps the rightmost dimension contiguous.
  • layout_left_padded keeps the leftmost dimension contiguous.
  • Static padding is encoded as the layout template argument.
  • Runtime padding uses std::dynamic_extent as the layout template argument and stores the stride in the mapping.
  • The mappings provide standard mdspan mapping observers such as extents(), required_span_size(), stride(r), is_unique(), is_exhaustive(), and is_strided().
  • Conversion constructors cover compatible classical, strided, and same-family padded mappings.

Tests

The padded-layout tests are added to dune/common/std/test/mappingtest.cc.

They cover:

  • layout_left_padded
  • layout_right_padded
  • static padding
  • conversion from layout_stride
  • conversion from same-family padded mappings
  • rank-1 compatibility with the opposite classical layout
Edited by Simon Praetorius

Merge request reports

Loading