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

33 KiB
Raw Permalink Blame History

[mdspan.sub]

23 Containers library [containers]

23.7 Views [views]

23.7.3 Multidimensional access [views.multidim]

23.7.3.7 submdspan [mdspan.sub]

23.7.3.7.1 Overview [mdspan.sub.overview]

1

#

The submdspan facilities create a new mdspan viewing a subset of elements of an existing input mdspan.

The subset viewed by the created mdspan is determined by the SliceSpecifier arguments.

2

#

For each function defined in [mdspan.sub] that takes a parameter pack named slices as an argument:

let index_type be

M::index_type if the function is a member of a class M,

otherwise, remove_reference_t<decltype(src)>::index_type if the function has a parameter named src,

otherwise, the same type as the function's template argument IndexType;

let rank be the number of elements in slices;

let sk be the kth element of slices;

let Sk be the type of sk; and

let map-rank be an array<size_t, rank> such that for each k in the range [0, rank),map-rank[k] equals:

dynamic_extent if Sk models convertible_to<index_type>,

otherwise, the number of types Sj with j<k that do not model convertible_to<index_type>.

23.7.3.7.2 strided_slice [mdspan.sub.strided.slice]

1

#

strided_slice represents a set ofextent regularly spaced integer indices.

The indices start at offset, and increase by increments of stride.

🔗

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 has the data members and special members specified above.

It has no base classes or members other than those specified.

3

#

Mandates: OffsetType, ExtentType, and StrideType are signed or unsigned integer types, or model integral-constant-like.

[Note 1:

strided_slice{.offset = 1, .extent = 10, .stride = 3} indicates the indices 1, 4, 7, and 10.

Indices are selected from the half-open interval [1, 1 + 10).

— end note]

23.7.3.7.3 submdspan_mapping_result [mdspan.sub.map.result]

1

#

Specializations of submdspan_mapping_result are returned by overloads of submdspan_mapping.

🔗

namespace std {templatestruct submdspan_mapping_result {no_unique_address LayoutMapping mapping = LayoutMapping(); size_t offset{}; };}

2

#

submdspan_mapping_result has the data members and special members specified above.

It has no base classes or members other than those specified.

3

#

LayoutMapping shall meet the layout mapping requirements ([mdspan.layout.policy.reqmts]).

23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]

🔗

`template constexpr T de-ice(T val) { return val; } template<integral-constant-like T> constexpr auto de-ice(T) { return T::value; }

template<class IndexType, size_t k, class... SliceSpecifiers> constexpr IndexType first_(SliceSpecifiers... slices); `

1

#

Mandates: IndexType is a signed or unsigned integer type.

2

#

Let ϕk denote the following value:

sk if Sk models convertible_to;

otherwise,get<0>(sk) if Sk models index-pair-like;

otherwise,de-ice(sk.offset) if Sk is a specialization of strided_slice;

otherwise,0.

3

#

Preconditions: ϕk is representable as a value of type IndexType.

4

#

Returns: extents::index-cast•k).

🔗

template<size_t k, class Extents, class... SliceSpecifiers> constexpr auto last_(const Extents& src, SliceSpecifiers... slices);

5

#

Mandates: Extents is a specialization of extents.

6

#

Let index_type be typename Extents::index_type.

7

#

Let λk denote the following value:

de-ice(sk) + 1 if Sk models convertible_to<index_type>; otherwise

get<1>(sk) if Sk models index-pair-like<index_type>; otherwise

de-ice(sk.offset) +de-ice(sk.extent) if Sk is a specialization of strided_slice; otherwise

src.extent(k).

8

#

Preconditions: λk is representable as a value of type index_type.

9

#

Returns: Extents::index-cast(λk).

🔗

template<class IndexType, size_t N, class... SliceSpecifiers> constexpr array<IndexType, sizeof...(SliceSpecifiers)> src-indices(const array<IndexType, N>& indices, SliceSpecifiers... slices);

10

#

Mandates: IndexType is a signed or unsigned integer type.

11

#

Returns: An array<IndexType, sizeof...(SliceSpecifiers)> src_idx such that for each k in the range [0, sizeof...(SliceSpecifiers)),src_idx[k] equals

first_<IndexType, k>(slices...) for each k where map-rank[k] equalsdynamic_extent,

otherwise,first_<IndexType, k>(slices...) +indices[map-rank[k]].

23.7.3.7.5 submdspan_extents function [mdspan.sub.extents]

🔗

template<class IndexType, size_t... Extents, class... SliceSpecifiers> constexpr auto submdspan_extents(const extents<IndexType, Extents...>& src, SliceSpecifiers... slices);

1

#

Constraints: sizeof...(slices) equals sizeof...(Extents).

2

#

Mandates: For each rank index k of src.extents(), exactly one of the following is true:

Sk models convertible_to,

Sk models index-pair-like,

is_convertible_v<Sk, full_extent_t> is true, or

Sk is a specialization of strided_slice.

3

#

Preconditions: For each rank index k of src.extents(), all of the following are true:

if Sk is a specialization of strided_slice

sk.extent=0, or

sk.stride>0

0 ≤ first_<IndexType, k>(slices...) ≤ last_(src, slices...) ≤ src.extent(k)

4

#

Let SubExtents be a specialization of extents such that:

SubExtents::rank() equals the number of k such thatSk does not model convertible_to; and

for each rank index k of Extents such thatmap-rank[k] != dynamic_extent is true,SubExtents::static_extent(map-rank[k]) equals:

Extents::static_extent(k) if is_convertible_v<Sk, full_extent_t> is true; otherwise

de-ice(tuple_element_t<1, Sk>()) -de-ice(tuple_element_t<0, Sk>()) if Sk models index-pair-like, and both tuple_element_t<0, Sk> and tuple_element_t<1, Sk> model integral-constant-like; otherwise

0, if Sk is a specialization of strided_slice, whose extent_type models integral-constant-like, for which extent_type() equals zero; otherwise

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;

otherwise, dynamic_extent.

5

#

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:

sk.extent == 0 ? 0 : 1 + (de-ice(sk.extent) - 1) / de-ice(sk.stride) if Sk is a specialization of strided_slice,

otherwise,last_(src, slices...) - first_<IndexType, k>(slices...).

23.7.3.7.6 Specializations of submdspan_mapping [mdspan.sub.map]

23.7.3.7.6.1 Common [mdspan.sub.map.common]

1

#

The following elements apply to all functions in [mdspan.sub.map].

2

#

Constraints: sizeof...(slices) equals extents_type::rank().

3

#

Mandates: For each rank index k of extents(), exactly one of the following is true:

Sk models convertible_to<index_type>,

Sk models index-pair-like<index_type>,

is_convertible_v<Sk, full_extent_t> is true, or

Sk is a specialization of strided_slice.

4

#

Preconditions: For each rank index k of extents(), all of the following are true:

if Sk is a specialization of strided_slice,sk.extent is equal to zero orsk.stride is greater than zero; and

0 ≤ first_<index_type, k>(slices...)
0 ≤ last_(extents(), slices...)
0 ≤ extents().extent(k)

5

#

Let sub_ext be the result of submdspan_extents(extents(), slices...) and let SubExtents be decltype(sub_ext).

6

#

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:

stride(k) * de-ice(sk.stride) if Sk is a specialization of strided_slice andsk.stride < sk.extent is true;

otherwise, stride(k).

7

#

Let P be a parameter pack such that is_same_v<make_index_sequence<rank()>, index_sequence<P...>> is true.

8

#

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().

Otherwise, let offset be a value of type size_t equal to(*this)(first_<index_type, P>(slices...)...).

9

#

Given a layout mapping type M, a type S is aunit-stride slice for M if

S is a specialization of strided_slice where S::stride_type models integral-constant-like and S::stride_type::value equals 1,

S models index-pair-like<M::index_type>, or

is_convertible_v<S, full_extent_t> is true.

23.7.3.7.6.2 layout_left specialization of submdspan_mapping [mdspan.sub.map.left]

🔗

template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_left::mapping<Extents>::submdspan-mapping-impl( SliceSpecifiers... slices) const -> see below;

1

#

Returns:

submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if SubExtents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if

for each k in the range [0, SubExtents::rank() - 1)), is_convertible_v<Sk, full_extent_t> is true; and

for k equal to SubExtents::rank() - 1, Sk is a unit-stride slice for mapping;

[Note 1: If the above conditions are true, all Sk with k larger than SubExtents::rank() - 1 are convertible to index_type. — end note]

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:

S0 is a unit-stride slice for mapping; and

for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<Sk, full_extent_t> is true; and

for k equal to u + SubExtents::rank() - 1,Sk is a unit-stride slice for mapping;

and where S_static is:

dynamic_extent, if static_extent(k) is dynamic_extent for any k in the range [0, u + 1),

otherwise, the product of all valuesstatic_extent(k) for k in the range [0, u + 1);

otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}

23.7.3.7.6.3 layout_right specialization of submdspan_mapping [mdspan.sub.map.right]

🔗

template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_right::mapping<Extents>::submdspan-mapping-impl( SliceSpecifiers... slices) const -> see below;

1

#

Returns:

submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset}, if SubExtents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if

for each k in the range [rank_ - SubExtents::rank() + 1, rank_), is_convertible_v<Sk, full_extent_t> is true; and

for k equal to _rank - SubExtents::rank(), Sk is a unit-stride slice for mapping;

[Note 1: If the above conditions are true, all Sk with k<_rank - SubExtents::rank() are convertible to index_type. — end note]

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:

for k equal to rank_ - 1,Sk is a unit-stride slice for mapping; and

for each k in the range [rank_ - SubExtents::rank() - u + 1, rank_ - u - 1),is_convertible_v<Sk, full_extent_t> is true; and

for k equal to rank_ - SubExtents::rank() - u,
Sk is a unit-stride slice for mapping;

and where S_static is:

dynamic_extent, if static_extent(k) is dynamic_extent for any k in the range [rank_ - u - 1, rank_),

otherwise, the product of all valuesstatic_extent(k) for k in the range [rank_ - u - 1, rank_);

otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}

23.7.3.7.6.4 layout_stride specialization of submdspan_mapping [mdspan.sub.map.stride]

🔗

template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_stride::mapping<Extents>::submdspan-mapping-impl( SliceSpecifiers... slices) const -> see below;

1

#

Returns:

submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}

23.7.3.7.6.5 layout_left_padded specialization of submdspan_mapping [mdspan.sub.map.leftpad]

🔗

template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_left_padded::mapping<Extents>::submdspan-mapping-impl( SliceSpecifiers... slices) const -> see below;

1

#

Returns:

submdspan_mapping_result{*this, 0}, if Extents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if rank_ == 1 is true orSubExtents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_left::mapping(sub_ext), offset}, if

SubExtents::rank() == 1 is true and

S0 is a unit-stride slice for mapping;

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:

S0 is a unit-stride slice for mapping; and

for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<Sk, full_extent_t> is true; and

for k equal to u + SubExtents::rank() - 1,Sk is a unit-stride slice for mapping;

where S_static is:

dynamic_extent, if static-padding-stride is dynamic_extent orstatic_extent(k) is dynamic_extent for any k in the range [1, u + 1),

otherwise, the product of static-padding-stride and all values static_extent(k) for k in the range [1, u + 1);

otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}

23.7.3.7.6.6 layout_right_padded specialization of submdspan_mapping [mdspan.sub.map.rightpad]

🔗

template<class Extents> template<class... SliceSpecifiers> constexpr auto layout_right_padded::mapping<Extents>::submdspan-mapping-impl( SliceSpecifiers... slices) const -> see below;

1

#

Returns:

submdspan_mapping_result{*this, 0}, if rank_ == 0 is true;

otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset},
if rank_ == 1 is true orSubExtents::rank() == 0 is true;

otherwise,submdspan_mapping_result{layout_right::mapping(sub_ext), offset}, if

SubExtents::rank() == 1 is true and

for k equal to rank_ - 1,Sk is a unit-stride slice for mapping;

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:

for k equal to rank_ - 1,Sk is a unit-stride slice for mapping; and

for each k in the range [rank_ - SubExtents::rank() - u + 1, rank_ - u - 1)),is_convertible_v<Sk, full_extent_t> is true; and

for k equal to rank_ - SubExtents::rank() - u,
Sk is a unit-stride slice for mapping;

and where S_static is:

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,

otherwise, the product of static-padding-stride and all values static_extent(k) with k in the range [rank_ - u - 1, rank_ - 1);

otherwise,submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}

23.7.3.7.7 submdspan function template [mdspan.sub.sub]

🔗

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

#

Let index_type be typename Extents::index_type.

2

#

Let sub_map_offset be the result ofsubmdspan_mapping(src.mapping(), slices...).

[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]).

— end note]

3

#

Constraints:

sizeof...(slices) equals Extents::rank(), and

the expression submdspan_mapping(src.mapping(), slices...) is well-formed when treated as an unevaluated operand.

4

#

Mandates:

  • (4.1)

    decltype(submdspan_mapping(src.mapping(), slices...)) is a specialization of submdspan_mapping_result.

  • (4.2)

    is_same_v<remove_cvref_t<decltype(sub_map_offset.mapping.extents())>,decltype(submdspan_extents(src.mapping(), slices...))> is true.

  • (4.3)

    For each rank index k of src.extents(), exactly one of the following is true:

Sk models convertible_to<index_type>,

Sk models index-pair-like<index_type>,

is_convertible_v<Sk, full_extent_t> is true, or

Sk is a specialization of strided_slice.

5

#

Preconditions:

For each rank index k of src.extents(), all of the following are true:

if Sk is a specialization of strided_slice + (5.1.1.1) sk.extent=0, or

+
      [(5.1.1.2)](#sub-5.1.1.2)

sk.stride>0

0 ≤ first_<index_type, k>(slices...) ≤ last_(src.extents(), slices...) ≤ src.extent(k)

sub_map_offset.mapping.extents() == submdspan_extents(src.mapping(), slices...) is true; and

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.

[Note 2:

These conditions ensure that the mapping returned by submdspan_mapping matches the algorithmically expected index-mapping given the slice specifiers.

— end note]

6

#

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

#

[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.

It does so by reusing a function zero_2d that takes a rank-2 mdspan.

// 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]