[mdspan.sub] (original) (raw)
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]
23.7.3.7.2 strided_slice [mdspan.sub.strided.slice]
23.7.3.7.3 submdspan_mapping_result [mdspan.sub.map.result]
23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]
23.7.3.7.5 submdspan_extents function [mdspan.sub.extents]
23.7.3.7.6 Specializations of submdspan_mapping [mdspan.sub.map]
23.7.3.7.6.1 Common [mdspan.sub.map.common]
23.7.3.7.6.2 layout_left specialization of submdspan_mapping [mdspan.sub.map.left]
23.7.3.7.6.3 layout_right specialization of submdspan_mapping [mdspan.sub.map.right]
23.7.3.7.6.4 layout_stride specialization of submdspan_mapping [mdspan.sub.map.stride]
23.7.3.7.6.5 layout_left_padded specialization of submdspan_mapping [mdspan.sub.map.leftpad]
23.7.3.7.6.6 layout_right_padded specialization of submdspan_mapping [mdspan.sub.map.rightpad]
23.7.3.7.7 submdspan function template [mdspan.sub.sub]
23.7.3.7.1 Overview [mdspan.sub.overview]
The submdspan facilities create a new mdspanviewing a subset of elements of an existing input mdspan.
The subset viewed by the created mdspan is determined by the SliceSpecifier arguments.
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 be the element of slices;
- let be the type of ; 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 models convertible_to<index_type>,
- otherwise, the number of types with that do not model convertible_to<index_type>.
23.7.3.7.2 strided_slice [mdspan.sub.strided.slice]
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{};};}
strided_slice has the data members and special members specified above.
It has no base classes or members other than those specified.
Mandates: OffsetType, ExtentType, and StrideTypeare 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]
Specializations of submdspan_mapping_resultare returned by overloads of submdspan_mapping.
namespace std { template<class LayoutMapping> struct submdspan_mapping_result { [[no_unique_address]] LayoutMapping mapping = LayoutMapping(); size_t offset{};};}
submdspan_mapping_result has the data members and special members specified above.
It has no base classes or members other than those specified.
23.7.3.7.4 Exposition-only helpers [mdspan.sub.helpers]
template<class T> constexpr T _de-ice_(T val) { return val; } template<[_integral-constant-like_](span.syn#concept:integral-constant-like "23.7.2.1 Header <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);
Mandates: IndexType is a signed or unsigned integer type.
Let denote the following value:
- if models convertible_to<IndexType>;
- otherwise,get<0>()if models index-pair-like<IndexType>;
- otherwise,de-ice(.offset)if is a specialization of strided_slice;
- otherwise,0.
Preconditions: is representable as a value of type IndexType.
Returns: extents<IndexType>::index-cast().
template<size_t k, class Extents, class... SliceSpecifiers> constexpr auto _last_(const Extents& src, SliceSpecifiers... slices);
Mandates: Extents is a specialization of extents.
Let index_type be typename Extents::index_type.
Let denote the following value:
- de-ice() + 1if models convertible_to<index_type>; otherwise
- get<1>()if models index-pair-like<index_type>; otherwise
- de-ice(.offset) + de-ice(.extent)if is a specialization of strided_slice; otherwise
- src.extent(k).
Preconditions: is representable as a value of type index_type.
Returns: Extents::index-cast().
template<class IndexType, size_t N, class... SliceSpecifiers> constexpr array<IndexType, sizeof...(SliceSpecifiers)> _src-indices_(const array<IndexType, N>& indices, SliceSpecifiers... slices);
Mandates: IndexType is a signed or unsigned integer type.
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 kwhere _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);
Constraints: sizeof...(slices) equals sizeof...(Extents).
Mandates: For each rank index k of src.extents(), exactly one of the following is true:
- models convertible_to<IndexType>,
- models index-pair-like<IndexType>,
- is_convertible_v<, full_extent_t> is true, or
- is a specialization of strided_slice.
Preconditions: For each rank index k of src.extents(), all of the following are true:
- if is a specialization of strided_slice
- , or
- 0 ≤ first_<IndexType, k>(slices...) ≤ last_<k>(src, slices...) ≤ src.extent(k)
Let SubExtents be a specialization of extents such that:
- SubExtents::rank() equals the number of k such that does not model convertible_to<IndexType>; and
- for each rank index k of Extents such that_map-rank_[k] != dynamic_extent is true,SubExtents::static_extent(_map-rank_[k]) equals:
- Extents::static_extent(k) if is_convertible_v<, full_extent_t> is true; otherwise
- de-ice(tuple_element_t<1, >()) - de-ice(tuple_element_t<0, >()) if models index-pair-like<IndexType>, and both tuple_element_t<0, > andtuple_element_t<1, > model integral-constant-like; otherwise
- 0, if is a specialization of strided_slice, whoseextent_type models integral-constant-like, for which extent_type() equals zero; otherwise
- 1 + (de-ice(::extent_type()) - 1) / de-ice(::stride_type()), if is a specialization of strided_slice whoseextent_type and stride_type model integral-constant-like;
- otherwise,dynamic_extent.
Returns: A value ext of type SubExtents such that for each kfor which _map-rank_[k] != dynamic_extent is true,ext.extent(_map-rank_[k]) equals:
- .extent == 0 ? 0 : 1 + (de-ice(.extent) - 1) / de-ice(.stride)if is a specialization of strided_slice,
- otherwise,last_<k>(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]
The following elements apply to all functions in [mdspan.sub.map].
Constraints: sizeof...(slices) equals extents_type::rank().
Mandates: For each rank index k of extents(), exactly one of the following is true:
- models convertible_to<index_type>,
- models index-pair-like<index_type>,
- is_convertible_v<, full_extent_t> is true, or
- is a specialization of strided_slice.
Preconditions: For each rank index k of extents(), all of the following are true:
- if is a specialization of strided_slice,.extent is equal to zero or.stride is greater than zero; and
- 0 ≤ first_<index_type, k>(slices...)
0 ≤ last_<k>(extents(), slices...)
0 ≤ extents().extent(k)
Let sub_ext be the result of submdspan_extents(extents(), slices...) and let SubExtents be decltype(sub_ext).
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(.stride)if is a specialization of strided_slice and.stride < .extent is true;
- otherwise, stride(k).
Let P be a parameter pack such that is_same_v<make_index_sequence<rank()>, index_sequence<P...>>is true.
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...)...).
Given a layout mapping type M, a type S is aunit-stride slice for M if
- S is a specialization of strided_slicewhere S::stride_type models integral-constant-likeand 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_;
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<, full_extent_t> is true; and
- for k equal to SubExtents::rank() - 1, is a unit-stride slice for mapping;
[Note 1:
If the above conditions are true, all with k larger than SubExtents::rank() - 1are 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 is the smallest value p larger than zero for which is a unit-stride slice for mapping, the following conditions are met:
- is a unit-stride slice for mapping; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<, full_extent_t> is true; and
- for k equal to u + SubExtents::rank() - 1, is a unit-stride slice for mapping;
and where S_static is: - dynamic_extent, if static_extent(k) is dynamic_extentfor 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_;
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
- otherwise,submdspan_mapping_result{layout_right_padded<S_static>::mapping(sub_ext, stride(rank_ - u - 2)), offset} if for a value u for which is the largest value p smaller than rank_ - 1for which is a unit-stride slice for mapping, the following conditions are met:
- for k equal to rank_ - 1, 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<, full_extent_t> is true; and
- for k equal to rank_ - SubExtents::rank() - u,
is a unit-stride slice for mapping;
and where S_static is: - dynamic_extent, if static_extent(k) is dynamic_extentfor 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_;
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_;
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
- 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 ufor which u + 1 is the smallest value p larger than zero for which is a unit-stride slice for mapping, the following conditions are met:
- is a unit-stride slice for mapping; and
- for each k in the range [u + 1, u + SubExtents::rank() - 1),is_convertible_v<, full_extent_t> is true; and
- for k equal to u + SubExtents::rank() - 1, 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_extentfor 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_;
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, 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 ufor which rank_ - u - 2is the largest value p smaller than rank_ - 1for which is a unit-stride slice for mapping, the following conditions are met:
- for k equal to rank_ - 1, 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<, full_extent_t> is true; and
- for k equal to rank_ - SubExtents::rank() - u,
is a unit-stride slice for mapping;
and where S_static is: - dynamic_extentif 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_;
Let index_type be typename Extents::index_type.
Let sub_map_offset be the result ofsubmdspan_mapping(src.mapping(), slices...).
[Note 1:
This invocation of submdspan_mappingselects 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_]
Constraints:
- sizeof...(slices) equals Extents::rank(), and
- the expression submdspan_mapping(src.mapping(), slices...)is well-formed when treated as an unevaluated operand.
Mandates:
- decltype(submdspan_mapping(src.mapping(), slices...))is a specialization of submdspan_mapping_result.
- is_same_v<remove_cvref_t<decltype(sub_map_offset.mapping.extents())>, decltype(submdspan_extents(src.mapping(), slices...))>is true.
- For each rank index k of src.extents(), exactly one of the following is true:
- models convertible_to<index_type>,
- models index-pair-like<index_type>,
- is_convertible_v<, full_extent_t> is true, or
- is a specialization of strided_slice.
Preconditions:
- For each rank index k of src.extents(), all of the following are true:
- if is a specialization of strided_slice
* , or - 0 ≤ first_<index_type, k>(slices...) ≤ last_<k>(src.extents(), slices...) ≤ src.extent(k)
- if is a specialization of strided_slice
- 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_mappingmatches the algorithmically expected index-mapping given the slice specifiers.
— _end note_]
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()));
[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_2dthat takes a rank-2 mdspan.
template<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;} template<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_]