[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​::​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 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.4 Concept convertible_­to [concept.convertible]"), * [(2.5.2)](#overview-2.5.2) otherwise, the number of types Sj with j[.](#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 {templatestruct 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.1 Header 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 {templatestruct 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.3 Layout 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 constexpr T de-ice(T val) { return val; } template<[integral-constant-like](span.syn#concept:integral-constant-like "23.7.2.1 Header synopsis [span.syn]") T> constexpr auto de-ice(T) { return T::value; } template 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.4 Concept convertible_­to [concept.convertible]"); - [(2.2)](#helpers-2.2) otherwise,get<0>(sk) if Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2 Header synopsis [mdspan.syn]"); - [(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​::​*index-cast*(ϕk)[.](#helpers-4.sentence-1) [🔗](#lib:last_) `template 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.4 Concept convertible_­to [concept.convertible]"); otherwise - [(7.2)](#helpers-7.2) get<1>(sk) if Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2 Header synopsis [mdspan.syn]"); 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 constexpr array src-indices(const array& 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 src_idx such that for each k in the range [0, sizeof...(SliceSpecifiers)),src_idx[k] equals - [(11.1)](#helpers-11.1) *first_*(slices...) for each k where *map-rank*[k] equalsdynamic_extent, - [(11.2)](#helpers-11.2) otherwise,*first_*(slices...) +indices[*map-rank*[k]]. #### [23.7.3.7.5](#extents) submdspan_extents function [[mdspan.sub.extents]](mdspan.sub.extents) [🔗](#lib:submdspan_extents) `template constexpr auto submdspan_extents(const 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.4 Concept convertible_­to [concept.convertible]"), - [(2.2)](#extents-2.2) Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2 Header synopsis [mdspan.syn]"), - [(2.3)](#extents-2.3) is_convertible_v 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_*(slices...) ≤ *last_*(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.4 Concept convertible_­to [concept.convertible]"); 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 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.2 Header synopsis [mdspan.syn]"), 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.1 Header 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_*(src, slices...) - *first_*(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.6 Specializations 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.4 Concept convertible_­to [concept.convertible]"), - [(3.2)](#map.common-3.2) Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2 Header synopsis [mdspan.syn]"), - [(3.3)](#map.common-3.3) is_convertible_v 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_*(slices...) 0 ≤ *last_*(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 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, index_sequence> is true[.](#map.common-7.sentence-1) [8](#map.common-8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/containers.tex#L25656) If *first_*(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_*(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.1 Common [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.1 Header 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.2 Header synopsis [mdspan.syn]"), or - [(9.3)](#map.common-9.3) is_convertible_v 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 template constexpr auto layout_left::mapping::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 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::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 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 template constexpr auto layout_right::mapping::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 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::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.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 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 template constexpr auto layout_stride::mapping::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 template constexpr auto layout_left_padded::mapping::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::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 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 template constexpr auto layout_right_padded::mapping::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::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 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 constexpr auto submdspan( const mdspan& 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.4 Argument-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,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.4 Concept convertible_­to [concept.convertible]"), * [(4.3.2)](#sub-4.3.2) Sk models [*index-pair-like*](mdspan.syn#concept:index-pair-like "23.7.3.2 Header synopsis [mdspan.syn]"), * [(4.3.3)](#sub-4.3.3) is_convertible_v 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_*(slices...) ≤ *last_*(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 mdspantemplatevoid zero_2d(mdspan 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 surfacetemplatevoid zero_surface(mdspan 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*]