Files
2025-10-25 03:02:53 +03:00

965 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[mdspan.sub]
# 23 Containers library [[containers]](./#containers)
## 23.7 Views [[views]](views#mdspan.sub)
### 23.7.3 Multidimensional access [[views.multidim]](views.multidim#mdspan.sub)
#### 23.7.3.7 submdspan [mdspan.sub]
#### [23.7.3.7.1](#overview) Overview [[mdspan.sub.overview]](mdspan.sub.overview)
[1](#overview-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25258)
The submdspan facilities create a new mdspan viewing a subset of elements of an existing input mdspan[.](#overview-1.sentence-1)
The subset viewed by the created mdspan is determined by
the SliceSpecifier arguments[.](#overview-1.sentence-2)
[2](#overview-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25264)
For each function defined in [mdspan.sub] that
takes a parameter pack named slices as an argument:
- [(2.1)](#overview-2.1)
let index_type be
* [(2.1.1)](#overview-2.1.1)
M::index_type if the function is a member of a class M,
* [(2.1.2)](#overview-2.1.2)
otherwise, remove_reference_t<decltype(src)>::index_type if the function has a parameter named src,
* [(2.1.3)](#overview-2.1.3)
otherwise,
the same type as the function's template argument IndexType;
- [(2.2)](#overview-2.2)
let rank be the number of elements in slices;
- [(2.3)](#overview-2.3)
let sk be the kth element of slices;
- [(2.4)](#overview-2.4)
let Sk be the type of sk; and
- [(2.5)](#overview-2.5)
let *map-rank* be an array<size_t, rank> such that
for each k in the range [0, rank),*map-rank*[k] equals:
* [(2.5.1)](#overview-2.5.1)
dynamic_extent if Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<index_type>,
* [(2.5.2)](#overview-2.5.2)
otherwise,
the number of types Sj with j<k that
do not model [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<index_type>[.](#overview-2.sentence-1)
#### [23.7.3.7.2](#strided.slice) strided_slice [[mdspan.sub.strided.slice]](mdspan.sub.strided.slice)
[1](#strided.slice-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25300)
strided_slice represents a set ofextent regularly spaced integer indices[.](#strided.slice-1.sentence-1)
The indices start at offset, and
increase by increments of stride[.](#strided.slice-1.sentence-2)
[🔗](#lib:strided_slice)
namespace std {template<class OffsetType, class ExtentType, class StrideType>struct strided_slice {using offset_type = OffsetType; using extent_type = ExtentType; using stride_type = StrideType; [[no_unique_address]] offset_type offset{}; [[no_unique_address]] extent_type extent{}; [[no_unique_address]] stride_type stride{}; };}
[2](#strided.slice-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25322)
strided_slice has the data members and special members specified above[.](#strided.slice-2.sentence-1)
It has no base classes or members other than those specified[.](#strided.slice-2.sentence-2)
[3](#strided.slice-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25326)
*Mandates*: OffsetType, ExtentType, and StrideType are signed or unsigned integer types, or
model [*integral-constant-like*](span.syn#concept:integral-constant-like "23.7.2.1Header <span> synopsis[span.syn]")[.](#strided.slice-3.sentence-1)
[*Note [1](#strided.slice-note-1)*:
strided_slice{.offset = 1, .extent = 10, .stride = 3} indicates the indices 1, 4, 7, and 10[.](#strided.slice-3.sentence-2)
Indices are selected from the half-open interval [1, 1 + 10)[.](#strided.slice-3.sentence-3)
— *end note*]
#### [23.7.3.7.3](#map.result) submdspan_mapping_result [[mdspan.sub.map.result]](mdspan.sub.map.result)
[1](#map.result-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25339)
Specializations of submdspan_mapping_result are returned by overloads of submdspan_mapping[.](#map.result-1.sentence-1)
[🔗](#lib:submdspan_mapping_result)
namespace std {template<class LayoutMapping>struct submdspan_mapping_result {[[no_unique_address]] LayoutMapping mapping = LayoutMapping();
size_t offset{}; };}
[2](#map.result-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25354)
submdspan_mapping_result has
the data members and special members specified above[.](#map.result-2.sentence-1)
It has no base classes or members other than those specified[.](#map.result-2.sentence-2)
[3](#map.result-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25359)
LayoutMapping shall meet
the layout mapping requirements ([[mdspan.layout.policy.reqmts]](mdspan.layout.policy.reqmts "23.7.3.4.3Layout mapping policy requirements"))[.](#map.result-3.sentence-1)
#### [23.7.3.7.4](#helpers) Exposition-only helpers [[mdspan.sub.helpers]](mdspan.sub.helpers)
[🔗](#lib:de-ice)
`template<class T>
constexpr T de-ice(T val) { return val; }
template<[integral-constant-like](span.syn#concept:integral-constant-like "23.7.2.1Header <span> synopsis[span.syn]") T>
constexpr auto de-ice(T) { return T::value; }
template<class IndexType, size_t k, class... SliceSpecifiers>
constexpr IndexType first_(SliceSpecifiers... slices);
`
[1](#helpers-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25378)
*Mandates*: IndexType is a signed or unsigned integer type[.](#helpers-1.sentence-1)
[2](#helpers-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25383)
Let ϕk denote the following value:
- [(2.1)](#helpers-2.1)
sk if Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<IndexType>;
- [(2.2)](#helpers-2.2)
otherwise,get<0>(sk) if Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<IndexType>;
- [(2.3)](#helpers-2.3)
otherwise,*de-ice*(sk.offset) if Sk is a specialization of strided_slice;
- [(2.4)](#helpers-2.4)
otherwise,0[.](#helpers-2.sentence-1)
[3](#helpers-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25401)
*Preconditions*: ϕk is representable as a value of type IndexType[.](#helpers-3.sentence-1)
[4](#helpers-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25405)
*Returns*: extents<IndexType>::*index-cast*(ϕk)[.](#helpers-4.sentence-1)
[🔗](#lib:last_)
`template<size_t k, class Extents, class... SliceSpecifiers>
constexpr auto last_(const Extents& src, SliceSpecifiers... slices);
`
[5](#helpers-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25417)
*Mandates*: Extents is a specialization of extents[.](#helpers-5.sentence-1)
[6](#helpers-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25421)
Let index_type be typename Extents::index_type[.](#helpers-6.sentence-1)
[7](#helpers-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25425)
Let λk denote the following value:
- [(7.1)](#helpers-7.1)
*de-ice*(sk) + 1 if Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<index_type>; otherwise
- [(7.2)](#helpers-7.2)
get<1>(sk) if Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<index_type>; otherwise
- [(7.3)](#helpers-7.3)
*de-ice*(sk.offset) +*de-ice*(sk.extent) if Sk is a specialization of strided_slice; otherwise
- [(7.4)](#helpers-7.4)
src.extent(k)[.](#helpers-7.sentence-1)
[8](#helpers-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25443)
*Preconditions*: λk is representable as a value of type index_type[.](#helpers-8.sentence-1)
[9](#helpers-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25447)
*Returns*: Extents::*index-cast*(λk)[.](#helpers-9.sentence-1)
[🔗](#lib:src-indices)
`template<class IndexType, size_t N, class... SliceSpecifiers>
constexpr array<IndexType, sizeof...(SliceSpecifiers)>
src-indices(const array<IndexType, N>& indices, SliceSpecifiers... slices);
`
[10](#helpers-10)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25460)
*Mandates*: IndexType is a signed or unsigned integer type[.](#helpers-10.sentence-1)
[11](#helpers-11)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25464)
*Returns*: An array<IndexType, sizeof...(SliceSpecifiers)> src_idx such that
for each k in the range [0, sizeof...(SliceSpecifiers)),src_idx[k] equals
- [(11.1)](#helpers-11.1)
*first_*<IndexType, k>(slices...) for each k where *map-rank*[k] equalsdynamic_extent,
- [(11.2)](#helpers-11.2)
otherwise,*first_*<IndexType, k>(slices...) +indices[*map-rank*[k]].
#### [23.7.3.7.5](#extents) submdspan_extents function [[mdspan.sub.extents]](mdspan.sub.extents)
[🔗](#lib:submdspan_extents)
`template<class IndexType, size_t... Extents, class... SliceSpecifiers>
constexpr auto submdspan_extents(const extents<IndexType, Extents...>& src,
SliceSpecifiers... slices);
`
[1](#extents-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25496)
*Constraints*: sizeof...(slices) equals sizeof...(Extents)[.](#extents-1.sentence-1)
[2](#extents-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25500)
*Mandates*: For each rank index k of src.extents(),
exactly one of the following is true:
- [(2.1)](#extents-2.1)
Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<IndexType>,
- [(2.2)](#extents-2.2)
Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<IndexType>,
- [(2.3)](#extents-2.3)
is_convertible_v<Sk, full_extent_t> is true, or
- [(2.4)](#extents-2.4)
Sk is a specialization of strided_slice[.](#extents-2.sentence-1)
[3](#extents-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25511)
*Preconditions*: For each rank index k of src.extents(),
all of the following are true:
- [(3.1)](#extents-3.1)
if Sk is a specialization of strided_slice
* [(3.1.1)](#extents-3.1.1)
sk.extent=0, or
* [(3.1.2)](#extents-3.1.2)
sk.stride>0
- [(3.2)](#extents-3.2)
0 ≤ *first_*<IndexType, k>(slices...) ≤ *last_*<k>(src, slices...) ≤ src.extent(k)
[4](#extents-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25528)
Let SubExtents be a specialization of extents such that:
- [(4.1)](#extents-4.1)
SubExtents::rank() equals the number of k such thatSk does not model [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<IndexType>; and
- [(4.2)](#extents-4.2)
for each rank index k of Extents such that*map-rank*[k] != dynamic_extent is true,SubExtents::static_extent(*map-rank*[k]) equals:
* [(4.2.1)](#extents-4.2.1)
Extents::static_extent(k) if is_convertible_v<Sk, full_extent_t> is true;
otherwise
* [(4.2.2)](#extents-4.2.2)
*de-ice*(tuple_element_t<1, Sk>()) -*de-ice*(tuple_element_t<0, Sk>()) if Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<IndexType>, and
both tuple_element_t<0, Sk> and tuple_element_t<1, Sk> model [*integral-constant-like*](span.syn#concept:integral-constant-like "23.7.2.1Header <span> synopsis[span.syn]"); otherwise
* [(4.2.3)](#extents-4.2.3)
0,
if Sk is a specialization of strided_slice, whose extent_type models *integral-constant-like*,
for which extent_type() equals zero; otherwise
* [(4.2.4)](#extents-4.2.4)
1 + (*de-ice*(Sk::extent_type()) - 1) /*de-ice*(Sk::stride_type()),
if Sk is a specialization of strided_slice whose extent_type and stride_type model *integral-constant-like*;
* [(4.2.5)](#extents-4.2.5)
otherwise, dynamic_extent[.](#extents-4.sentence-1)
[5](#extents-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25573)
*Returns*: A value ext of type SubExtents such that
for each k for which *map-rank*[k] != dynamic_extent is true,ext.extent(*map-rank*[k]) equals:
- [(5.1)](#extents-5.1)
sk.extent == 0 ? 0 : 1 + (*de-ice*(sk.extent) - 1) / *de-ice*(sk.stride) if Sk is a specialization of strided_slice,
- [(5.2)](#extents-5.2)
otherwise,*last_*<k>(src, slices...) - *first_*<IndexType, k>(slices...)[.](#extents-5.sentence-1)
#### [23.7.3.7.6](#map) Specializations of submdspan_mapping [[mdspan.sub.map]](mdspan.sub.map)
#### [23.7.3.7.6.1](#map.common) Common [[mdspan.sub.map.common]](mdspan.sub.map.common)
[1](#map.common-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25594)
The following elements apply to all functions in [[mdspan.sub.map]](#map "23.7.3.7.6Specializations of submdspan_­mapping")[.](#map.common-1.sentence-1)
[2](#map.common-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25597)
*Constraints*: sizeof...(slices) equals extents_type::rank()[.](#map.common-2.sentence-1)
[3](#map.common-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25601)
*Mandates*: For each rank index k of extents(),
exactly one of the following is true:
- [(3.1)](#map.common-3.1)
Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<index_type>,
- [(3.2)](#map.common-3.2)
Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<index_type>,
- [(3.3)](#map.common-3.3)
is_convertible_v<Sk, full_extent_t> is true, or
- [(3.4)](#map.common-3.4)
Sk is a specialization of strided_slice[.](#map.common-3.sentence-1)
[4](#map.common-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25616)
*Preconditions*: For each rank index k of extents(),
all of the following are true:
- [(4.1)](#map.common-4.1)
if Sk is a specialization of strided_slice,sk.extent is equal to zero orsk.stride is greater than zero; and
- [(4.2)](#map.common-4.2)
0 ≤ *first_*<index_type, k>(slices...)
0 ≤ *last_*<k>(extents(), slices...)
0 ≤ extents().extent(k)
[5](#map.common-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25631)
Let sub_ext be
the result of submdspan_extents(extents(), slices...) and
let SubExtents be decltype(sub_ext)[.](#map.common-5.sentence-1)
[6](#map.common-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25636)
Let sub_strides be
an array<SubExtents::index_type, SubExtents::rank()> such that for each rank index k of extents() for which *map-rank*[k] is not dynamic_extent,sub_strides[*map-rank*[k]] equals:
- [(6.1)](#map.common-6.1)
stride(k) * *de-ice*(sk.stride) if Sk is a specialization of strided_slice andsk.stride < sk.extent is true;
- [(6.2)](#map.common-6.2)
otherwise, stride(k)[.](#map.common-6.sentence-1)
[7](#map.common-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25651)
Let P be a parameter pack
such that is_same_v<make_index_sequence<rank()>, index_sequence<P...>> is true[.](#map.common-7.sentence-1)
[8](#map.common-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25656)
If *first_*<index_type, k>(slices...) equals extents().extent(k) for any rank index k of extents(), then
let offset be a value of type size_t equal to(*this).required_span_size()[.](#map.common-8.sentence-1)
Otherwise,
let offset be a value of type size_t equal to(*this)(*first_*<index_type, P>(slices...)...)[.](#map.common-8.sentence-2)
[9](#map.common-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25666)
Given a layout mapping type M, a type S is a[*unit-stride slice for M*](#def:slice,unit-stride "23.7.3.7.6.1Common[mdspan.sub.map.common]") if
- [(9.1)](#map.common-9.1)
S is a specialization of strided_slice where S::stride_type models [*integral-constant-like*](span.syn#concept:integral-constant-like "23.7.2.1Header <span> synopsis[span.syn]") and S::stride_type::value equals 1,
- [(9.2)](#map.common-9.2)
S models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<M::index_type>, or
- [(9.3)](#map.common-9.3)
is_convertible_v<S, full_extent_t> is true[.](#map.common-9.sentence-1)
#### [23.7.3.7.6.2](#map.left) layout_left specialization of submdspan_mapping [[mdspan.sub.map.left]](mdspan.sub.map.left)
[🔗](#lib:layout_left::mapping,submdspan-mapping-impl)
`template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_left::mapping<Extents>::submdspan-mapping-impl(
SliceSpecifiers... slices) const -> see below;
`
[1](#map.left-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25688)
*Returns*:
- [(1.1)](#map.left-1.1)
submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- [(1.2)](#map.left-1.2)
otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true;
- [(1.3)](#map.left-1.3)
otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
* [(1.3.1)](#map.left-1.3.1)
for each k in the range [0, SubExtents::rank() - 1)), is_convertible_v<Sk, full_extent_t> is true; and
* [(1.3.2)](#map.left-1.3.2)
for k equal to SubExtents::rank() - 1, Sk is a unit-stride slice for mapping;
[*Note [1](#map.left-note-1)*:
If the above conditions are true,
all Sk with k larger than SubExtents::rank() - 1 are convertible to index_type[.](#map.left-1.3.sentence-1)
— *end note*]
- [(1.4)](#map.left-1.4)
otherwise,submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)),
offset} if for a value u for which u+1 is
the smallest value p larger than zero
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
* [(1.4.1)](#map.left-1.4.1)
S0 is a unit-stride slice for mapping; and
* [(1.4.2)](#map.left-1.4.2)
for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<Sk, full_extent_t> is true; and
* [(1.4.3)](#map.left-1.4.3)
for k equal to u + SubExtents::rank() - 1,Sk is a unit-stride slice for mapping;
and where S_static is:
* [(1.4.4)](#map.left-1.4.4)
dynamic_extent,
if static_extent(k) is dynamic_extent for any k in the range [0, u + 1),
* [(1.4.5)](#map.left-1.4.5)
otherwise, the product of all valuesstatic_extent(k) for k in the range [0, u + 1);
- [(1.5)](#map.left-1.5)
otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
#### [23.7.3.7.6.3](#map.right) layout_right specialization of submdspan_mapping [[mdspan.sub.map.right]](mdspan.sub.map.right)
[🔗](#lib:layout_right::mapping,submdspan-mapping-impl)
`template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_right::mapping<Extents>::submdspan-mapping-impl(
SliceSpecifiers... slices) const -> see below;
`
[1](#map.right-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25764)
*Returns*:
- [(1.1)](#map.right-1.1)
submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- [(1.2)](#map.right-1.2)
otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if SubExtents::rank() == 0 is true;
- [(1.3)](#map.right-1.3)
otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
* [(1.3.1)](#map.right-1.3.1)
for each k in the range [*rank_* - SubExtents::rank() + 1, *rank_*), is_convertible_v<Sk, full_extent_t> is true; and
* [(1.3.2)](#map.right-1.3.2)
for k equal to *_rank* - SubExtents::rank(), Sk is a unit-stride slice for mapping;
[*Note [1](#map.right-note-1)*:
If the above conditions are true,
all Sk with k<_rank - SubExtents::rank() are convertible to index_type[.](#map.right-1.3.sentence-1)
— *end note*]
- [(1.4)](#map.right-1.4)
otherwise,submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext,
stride(*rank_* - u - 2)), offset} if for a value u for which rank_−ˆ’2 is
the largest value p smaller than *rank_* - 1 for which Sp is a unit-stride slice for mapping,
the following conditions are met:
* [(1.4.1)](#map.right-1.4.1)
for k equal to *rank_* - 1,Sk is a unit-stride slice for mapping; and
* [(1.4.2)](#map.right-1.4.2)
for each k in the range
[*rank_* - SubExtents::rank() - u + 1, *rank_* - u - 1),is_convertible_v<Sk, full_extent_t> is true; and
* [(1.4.3)](#map.right-1.4.3)
for k equal to *rank_* - SubExtents::rank() - u,
Sk is a unit-stride slice for mapping;
and where S_static is:
* [(1.4.4)](#map.right-1.4.4)
dynamic_extent,
if static_extent(k) is dynamic_extent for any k in the range [*rank_* - u - 1, *rank_*),
* [(1.4.5)](#map.right-1.4.5)
otherwise, the product of all valuesstatic_extent(k) for k in the range [*rank_* - u - 1, *rank_*);
- [(1.5)](#map.right-1.5)
otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
#### [23.7.3.7.6.4](#map.stride) layout_stride specialization of submdspan_mapping [[mdspan.sub.map.stride]](mdspan.sub.map.stride)
[🔗](#lib:layout_stride::mapping,submdspan-mapping-impl)
`template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_stride::mapping<Extents>::submdspan-mapping-impl(
SliceSpecifiers... slices) const -> see below;
`
[1](#map.stride-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25843)
*Returns*:
- [(1.1)](#map.stride-1.1)
submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- [(1.2)](#map.stride-1.2)
otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
#### [23.7.3.7.6.5](#map.leftpad) layout_left_padded specialization of submdspan_mapping [[mdspan.sub.map.leftpad]](mdspan.sub.map.leftpad)
[🔗](#lib:layout_left_padded::mapping,submdspan-mapping-impl)
`template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_left_padded::mapping<Extents>::submdspan-mapping-impl(
SliceSpecifiers... slices) const -> see below;
`
[1](#map.leftpad-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25868)
*Returns*:
- [(1.1)](#map.leftpad-1.1)
submdspan_mapping_result{*this, 0},
if Extents::rank() == 0 is true;
- [(1.2)](#map.leftpad-1.2)
otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if *rank_* == 1 is true orSubExtents::rank() == 0 is true;
- [(1.3)](#map.leftpad-1.3)
otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset},
if
* [(1.3.1)](#map.leftpad-1.3.1)
SubExtents::rank() == 1 is true and
* [(1.3.2)](#map.leftpad-1.3.2)
S0 is a unit-stride slice for mapping;
- [(1.4)](#map.leftpad-1.4)
otherwise,submdspan_mapping_result{layout_left_padded<S_static>::mapping(sub_ext, stride(u + 1)),
offset} if for a value u for which u + 1 is the smallest value p larger than zero
for which Sp is a unit-stride slice for mapping,
the following conditions are met:
* [(1.4.1)](#map.leftpad-1.4.1)
S0 is a unit-stride slice for mapping; and
* [(1.4.2)](#map.leftpad-1.4.2)
for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<Sk, full_extent_t> is true; and
* [(1.4.3)](#map.leftpad-1.4.3)
for k equal to u + SubExtents::rank() - 1,Sk is a unit-stride slice for mapping;
where S_static is:
* [(1.4.4)](#map.leftpad-1.4.4)
dynamic_extent,
if *static-padding-stride* is dynamic_extent orstatic_extent(k) is dynamic_extent for any k in the range [1, u + 1),
* [(1.4.5)](#map.leftpad-1.4.5)
otherwise, the product of *static-padding-stride* and
all values static_extent(k) for k in the range [1, u + 1);
- [(1.5)](#map.leftpad-1.5)
otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
#### [23.7.3.7.6.6](#map.rightpad) layout_right_padded specialization of submdspan_mapping [[mdspan.sub.map.rightpad]](mdspan.sub.map.rightpad)
[🔗](#lib:layout_right_padded::mapping,submdspan-mapping-impl)
`template<class Extents>
template<class... SliceSpecifiers>
constexpr auto layout_right_padded::mapping<Extents>::submdspan-mapping-impl(
SliceSpecifiers... slices) const -> see below;
`
[1](#map.rightpad-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25939)
*Returns*:
- [(1.1)](#map.rightpad-1.1)
submdspan_mapping_result{*this, 0},
if *rank_* == 0 is true;
- [(1.2)](#map.rightpad-1.2)
otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if *rank_* == 1 is true orSubExtents::rank() == 0 is true;
- [(1.3)](#map.rightpad-1.3)
otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if
* [(1.3.1)](#map.rightpad-1.3.1)
SubExtents::rank() == 1 is true and
* [(1.3.2)](#map.rightpad-1.3.2)
for k equal to *rank_* - 1,Sk is a unit-stride slice for mapping;
- [(1.4)](#map.rightpad-1.4)
otherwise,submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext,
stride(*rank_* - u - 2)), offset} if for a value u for which *rank_* - u - 2 is the largest value p smaller than *rank_* - 1 for which Sp is a unit-stride slice for mapping,
the following conditions are met:
* [(1.4.1)](#map.rightpad-1.4.1)
for k equal to *rank_* - 1,Sk is a unit-stride slice for mapping; and
* [(1.4.2)](#map.rightpad-1.4.2)
for each k in the range
[*rank_* - SubExtents::rank() - u + 1, *rank_* - u - 1)),is_convertible_v<Sk, full_extent_t> is true; and
* [(1.4.3)](#map.rightpad-1.4.3)
for k equal to *rank_* - SubExtents::rank() - u,
Sk is a unit-stride slice for mapping;
and where S_static is:
* [(1.4.4)](#map.rightpad-1.4.4)
dynamic_extent if *static-padding-stride* is dynamic_extent or
for any k in the range [*rank_* - u - 1, *rank_* - 1)static_extent(k) is dynamic_extent,
* [(1.4.5)](#map.rightpad-1.4.5)
otherwise, the product of *static-padding-stride* and
all values static_extent(k) with k in the range [*rank_* - u - 1, *rank_* - 1);
- [(1.5)](#map.rightpad-1.5)
otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}
#### [23.7.3.7.7](#sub) submdspan function template [[mdspan.sub.sub]](mdspan.sub.sub)
[🔗](#lib:submdspan)
`template<class ElementType, class Extents, class LayoutPolicy,
class AccessorPolicy, class... SliceSpecifiers>
constexpr auto submdspan(
const mdspan<ElementType, Extents, LayoutPolicy, AccessorPolicy>& src,
SliceSpecifiers... slices) -> see below;
`
[1](#sub-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26016)
Let index_type be typename Extents::index_type[.](#sub-1.sentence-1)
[2](#sub-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26019)
Let sub_map_offset be the result ofsubmdspan_mapping(src.mapping(), slices...)[.](#sub-2.sentence-1)
[*Note [1](#sub-note-1)*:
This invocation of submdspan_mapping selects a function call via overload resolution
on a candidate set that includes the lookup set
found by argument-dependent lookup ([[basic.lookup.argdep]](basic.lookup.argdep "6.5.4Argument-dependent name lookup"))[.](#sub-2.sentence-2)
— *end note*]
[3](#sub-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26029)
*Constraints*:
- [(3.1)](#sub-3.1)
sizeof...(slices) equals Extents::rank(), and
- [(3.2)](#sub-3.2)
the expression submdspan_mapping(src.mapping(), slices...) is well-formed when treated as an unevaluated operand[.](#sub-3.sentence-1)
[4](#sub-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26039)
*Mandates*:
- [(4.1)](#sub-4.1)
decltype(submdspan_mapping(src.mapping(), slices...)) is a specialization of submdspan_mapping_result[.](#sub-4.1.sentence-1)
- [(4.2)](#sub-4.2)
is_same_v<remove_cvref_t<decltype(sub_map_offset.mapping.extents())>,decltype(submdspan_extents(src.mapping(), slices...))> is true[.](#sub-4.2.sentence-1)
- [(4.3)](#sub-4.3)
For each rank index k of src.extents(),
exactly one of the following is true:
* [(4.3.1)](#sub-4.3.1)
Sk models [convertible_to](concept.convertible#concept:convertible_to "18.4.4Concept convertible_­to[concept.convertible]")<index_type>,
* [(4.3.2)](#sub-4.3.2)
Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2Header <mdspan> synopsis[mdspan.syn]")<index_type>,
* [(4.3.3)](#sub-4.3.3)
is_convertible_v<Sk, full_extent_t> is true, or
* [(4.3.4)](#sub-4.3.4)
Sk is a specialization of strided_slice[.](#sub-4.3.sentence-1)
[5](#sub-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26062)
*Preconditions*:
- [(5.1)](#sub-5.1)
For each rank index k of src.extents(),
all of the following are true:
* [(5.1.1)](#sub-5.1.1)
if Sk is a specialization of strided_slice
+
[(5.1.1.1)](#sub-5.1.1.1)
sk.extent=0, or
+
[(5.1.1.2)](#sub-5.1.1.2)
sk.stride>0
* [(5.1.2)](#sub-5.1.2)
0 ≤ *first_*<index_type, k>(slices...) ≤ *last_*<k>(src.extents(), slices...) ≤ src.extent(k)
- [(5.2)](#sub-5.2)
sub_map_offset.mapping.extents() == submdspan_extents(src.mapping(), slices...) is true; and
- [(5.3)](#sub-5.3)
for each integer pack I which is a multidimensional index
in sub_map_offset.mapping.extents(),sub_map_offset.mapping(I...) + sub_map_offset.offset == src.mapping()(*src-indices*(array{I...}, slices...)) is true[.](#sub-5.sentence-1)
[*Note [2](#sub-note-2)*:
These conditions ensure that the mapping returned by submdspan_mapping matches the algorithmically expected index-mapping given the slice specifiers[.](#sub-5.sentence-2)
— *end note*]
[6](#sub-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26100)
*Effects*: Equivalent to:auto sub_map_result = submdspan_mapping(src.mapping(), slices...);return mdspan(src.accessor().offset(src.data_handle(), sub_map_result.offset),
sub_map_result.mapping, typename AccessorPolicy::offset_policy(src.accessor()));
[7](#sub-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L26111)
[*Example [1](#sub-example-1)*:
Given a rank-3 mdspan grid3d representing a three-dimensional grid
of regularly spaced points in a rectangular prism,
the function zero_surface sets all elements on
the surface of the 3-dimensional shape to zero[.](#sub-7.sentence-1)
It does so by reusing a function zero_2d that takes a rank-2 mdspan[.](#sub-7.sentence-2)
// zero out all elements in an mdspantemplate<class T, class E, class L, class A>void zero_2d(mdspan<T, E, L, A> a) {static_assert(a.rank() == 2); for (int i = 0; i < a.extent(0); i++)for (int j = 0; j < a.extent(1); j++) a[i, j] = 0;}// zero out just the surfacetemplate<class T, class E, class L, class A>void zero_surface(mdspan<T, E, L, A> grid3d) {static_assert(grid3d.rank() == 3);
zero_2d(submdspan(grid3d, 0, full_extent, full_extent));
zero_2d(submdspan(grid3d, full_extent, 0, full_extent));
zero_2d(submdspan(grid3d, full_extent, full_extent, 0));
zero_2d(submdspan(grid3d, grid3d.extent(0) - 1, full_extent, full_extent));
zero_2d(submdspan(grid3d, full_extent, grid3d.extent(1) - 1, full_extent));
zero_2d(submdspan(grid3d, full_extent, full_extent, grid3d.extent(2) - 1));} — *end example*]