This library provides two new layouts (only C++17 compatible) to be used along with mdspan
layout_contiguous_at_right,layout_contiguous_at_left.
The layout layout_contiguous_at_right (resp. layout_contiguous_at_left) ensures (uniqueness and) contiguity in the right (resp. left) most dimension. By default the layout_contiguous_at_right (resp. layout_contiguous_at_left) behaves as a layout_right (layout_left) by computing the dynamic strides from the extents.
Some algorithms can be accelerated by SIMD instructions. A typical situation is an inner loop with unit stride.
Among the different layouts provided by the standard mdspan, only the layout_right and layout_left can provide such compile-time information about the unit stride. If one wants to iterate over a subrange, two solutions are possible:
- apply
submdspanthat may lead to alayout_strideand thus loosing the compile-time information of a contiguous dimension, - shift the integer range starting from a non-zero value.
We aim at providing an intermediate layout between layout_right (resp. layout_left) and layout_stride that ensures the compile-time unit stride in the right (resp. left) most dimension. Subranges of this layout are preserved as long as the contiguous dimension exists.
They provide the same API as layout_stride.
layout_right->layout_contiguous_at_rightlayout_left->layout_contiguous_at_leftlayout_stride->layout_contiguous_at_right(potentially throwing if right most stride is not 1)layout_stride->layout_contiguous_at_left(potentially throwing if left most stride is not 1)
The free function submdspan is overloaded to handle these two layouts. In the case of a layout layout_contiguous_at_right (resp. layout_contiguous_at_left), submdspan returns a mdspan with layout layout_contiguous_at_right (resp. layout_contiguous_at_left) if the right (resp. left) most spec is not an integer.
Let us write these rules with regular expressions. Let us note
S = Single integerR = Range of integersF = Full range of integers
Case layout_contiguous_at_right:
- if slice specifications are of the form
.*(R|F)thenlayout_contiguous_at_right - else
layout_stride
Case layout_contiguous_at_left:
- if slice specifications are of the form
(R|F).*thenlayout_contiguous_at_left - else
layout_stride
Case layout_right:
- if slice specifications are of the form
S*R?F*thenlayout_right - else
layout_stride
Case layout_left:
- if slice specifications are of the form
F*R?S*thenlayout_left - else
layout_stride
Further rules could be added considering the rank and some compile-time values in the extent.
- the mapping is implemented once for any contiguous dimension (see the
contiguous_mappingclass) - all strides are stored, even the compile-time known unit stride