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
submdspan
that may lead to alayout_stride
and 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_right
layout_left
->layout_contiguous_at_left
layout_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 integer
R = Range of integers
F = 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_mapping
class) - all strides are stored, even the compile-time known unit stride