1 Revision History

1.1 P0009r10: Pre 2020-02-Prague Mailing

Switched to mpark/wg21 pandoc format

Add general description of span and mdspan

Removed mdspan_subspan expo only type; use basic_mdspan< see below > instead

expo only type; use see below instead Fixed typos in accessor table

Made editorial changes to wording based on San Diego feedback

Updated operational semantics subsection heading based on new style guidelines

1.2 P0009r9: Pre 2019-02-Kona Mailing

Wording fixes based on guidance: LWG small group at 2018-11-SanDiego

1.3 P0009r8: Pre 2018-11-SanDiego Mailing

Refinement based upon updated prototype / reference implementation

1.4 P0009r7: Post 2018-06-Rapperswil Mailing

wording reworked based on guidance: LWG review at 2018-06-Rapperswil

usage of span requires reference to C++20 working draft

requires reference to C++20 working draft namespace for library TS std::experimental::fundamentals_v3

1.5 P0009r6 : Pre 2018-06-Rapperswil Mailing

P0009r5 was not taken up at 2018-03-Jacksonville meeting. Related LEWG review of P0900 at 2018-03-Jacksonville meeting

LEWG Poll We want the ability to customize the access to elements of span (ability to restrict, etc):

< T, N, Accessor =...> spanT, N, Accessor

SF F N A SA 1 1 1 2 8

LEWG Poll We want the customization of basic_mdspan to be two concepts Mapper and Accessor (akin to Allocator design).

< T, Extents, Mapper, Accessor > basic_mdspanT, Extents, Mapper, Accessor < T, N ...> mdspanT, N

SF F N A SA 3 4 5 1 0

LEWG Poll: We want the customization of basic_mdspan to be an arbitrary (and potentially user-extensible) list of properties.

< T, Extents, Properties ...> basic_mdspanT, Extents, Properties

SF F N A SA 1 2 2 6 2

Changes from P0009r5 due to related LEWG reviews:

Replaced variadic property list with extents, layout mapping, and accessor properties.

Incorporated P0454r1. Added accessor policy concept. Renamed mdspan to basic_mdspan . Added a mdspan alias to basic_mdspan .



1.6 P0009r5 : Pre 2018-03-Jacksonville Mailing

LEWG review of P0009r4 at 2017-11-Albuquerque meeting

LEWG Poll: We should be able to index with span<int type[N]> (in addition to array).

SF F N A SA 2 11 1 1 0

Against comment - there is not a proven needs for this feature.

LEWG Poll: We should be able to index with 1d mdspan .

SF F N A SA 0 8 7 0 0

LEWG Poll: We should put the requirement on “rank() <= N” back to “rank()==N”.

Unanimous consent

LEWG Poll: With the editorial changes from small group, plus the above polls, forward this to LWG for Fundamentals v3.

Unanimous consent

Changes from P0009r4:

Removed nullptr constructor.

Added constexpr to indexing operator.

Indexing operator requires that rank()==sizeof...(indices) .

. Fixed typos in examples and moved them to appendix.

Converted note on how extentions to access properties may cause reference to be a proxy type to an “see below” to make it normative.

1.7 P0009r4 : Pre 2017-11-Albuquerque Mailing

LEWG review at 2017-03-Kona meeting

LEWG review of P0546r1 at 2017-03-Kona meeting

LEWG Poll: Should we have a single template that covers both single and multi-dimensional spans?

SF F N A SA 1 6 2 6 3

Changes from P0009r3:

Align with P0122r5 span proposal.

Rename to mdspan , multidimensional span, to align with span .

, multidimensional span, to align with . Move preferred array extents mechanism to appendix.

Expose codomain as a span .

. Add layout mapping concept.

1.8 P0009r3 : Post 2016-06-Oulu Mailing

LEWG review at 2016-06-Oulu

LEWG did not like the name array_ref , and suggested the following alternatives: - sci_span - numeric_span - multidimensional_span - multidim_span - mdspan - md_span - vla_span - multispan - multi_span

LEWG Poll: Are member begin() / end() still good?

SF F N A SA 0 2 4 3 1

LEWG Poll: Want this proposal to provide range-producing functions outside array_ref ?

SF F N A SA 0 1 3 2 3

LEWG Poll: Want a separate proposal to explore iteration design space?

SF F N A SA 9 1 0 0 0

Changes from P0009r2:

Removed iterator support; a future paper will be written on the subject.

Noted difference between multidimensional array versus language’s array-of-array-of-array…

Clearly describe requirements for the embedded type aliases ( element_type , reference , etc).

, , etc). Expanded description of how the variadic properties list would work.

Stopped allowing array_ref<T[N]> in addition to array_ref<extents<N>> .

in addition to . Clarified domain, codomain, and domain -> codomain mapping specifications.

Consistently use extent and extents for the multidimensional index space.

1.9 P0009r2 : Pre 2016-06-Oulu Mailing

LEWG review at 2016-02-Jacksonville.

Changes from P0009r1:

1.10 P0009r1 : Pre 2016-02-Jacksonville Mailing

LEWG review at 2015-10-Kona.

LEWG Poll: What should this feature be called?

Name # view 5 span 9 array_ref 6 slice 6 array_view 6 ref 0 array_span 7 basic_span 1 object_span 3 field 0

LEWG Poll: Do we want 0-length static extents?

SF F N A SA 3 4 2 3 0

LEWG POLL: Do we want the language to support syntaxes like X[3][][][5] ?

Syntax # view<int[3][0][][5], property1> 12 view<int, dimension<3, 0, dynamic_extent, 5>, property1> 4 view<int[3][0][dynamic_extent][5], property1> 5 view<int, 3, 0, dynamic_extent, 5, property1> 4 view<int, 3, 0, dynamic_extent, 5, properties<property1>> 2 view<arr<int, 3, 0, dynamic_extent, 5>, property1> 4 view<int[3][0][][5], properties<property1>> 9

LEWG POLL: Do we want the variadic property list in template args (either raw or in properties<> )? Note there is no precedence for this in the library.

SF F N A SA 3 6 3 0 0

LEWG POLL: Do we want the per-view bounds-checking knob?

SF F N A SA 3 4 1 2 1

Changes from P0009r0:

Renamed view to array_ref .

to . How are users allowed to add properties? Needs elaboration in paper.

view<int[][][]>::layout should be named.

should be named. Rename is_regular (possibly to is_affine ) to avoid overloading the term with the Regular concept.

(possibly to ) to avoid overloading the term with the concept. Make static span(), operator(), constructor, etc variadic.

Demonstrate the need for improper access in the paper.

In operator() , take integral types by value.

1.11 P0009r0 : Pre 2015-10-Kona Mailing

Original non-owning multidimensional array reference ( view ) paper with motivation, specification, and examples.

1.12 Related Activity

Related LEWG review of P0546r1 at 2017-11-Albuquerque meeting

LEWG Poll: span should specify the dynamic extent as the element type of the first template parameter rather than the (current) second template parameter

SF F N A SA 5 3 2 2 0

LEWG Poll: span should support the addition of access properties variadic template parameters

SF F N A SA 0 10 1 5 0

Authors agreed to bring a separate paper ([[P0900r0]]) discussing how the variadic properties will work.

2 Description

The proposed polymorphic multidimensional array reference ( mdspan ) defines types and functions for mapping multidimensional indices in its domain, a multidimensional index space, to the mdspan ’s codomain, elements of a contiguous span of objects. A multidimensional index space of rank R is the Cartesian product [0, N 0 ) ⨯ [0, N 1 ) ⨯ … ⨯ 0, N R-1 ) of half-open integer intervals. A multidimensional index is a element of a multidimensional index space. An mdspan has two policies: the layout mapping and the accessor. The layout mapping specifies the formula, and properties of the formula, for mapping a multidimensional index from the domain to an element in the codomain. The accessor is an extension point that allows modification of how elements are accessed. For example, [P0367 proposed a rich set of potential access properties.

A multidimensional array is not an array-of-array-of-array-of…

The multidimensional array abstraction has been fundamental to numerical computations for over five decades. However, the C/C++ language provides only a one-dimensional array abstraction which can be composed into array-of-array-of-array-of… types. While such types have some similarity to multidimensional arrays, they do not provide adequate multidimensional array functionality of this proposal. Two critical functionality differences are (1) multiple dynamic extents and (2) polymorphic mapping of multidimensional indices to element objects.

Optimized Implementation of Layout Mapping

We intend the layout mapping of a multidimensional index to be a constant-time constexpr operation that is trivially inlined and optimized when possible. Compiler vendors may apply optimizations such as loop invariant code motion, including partial evaluation of multidimensional index layout mappings when indices are loop invariant.

3 Editing Notes

The proposed changes are relative to the working draft of the standard as of N4842.

The � character is used to denote a placeholder section number, table number, or paragraph number which the editor shall determine.

Add the header <mdspan> to the “C++ library headers” table in [headers] in a place that respects the table’s current alphabetic order.

Add the header <mdspan> to the “Containers library summary” table in [containers.general] below the listing for <span> .

4 Wording

The � character is used to denote a placeholder section number which the editor shall determine.

Make the following changes to 22.7.1 [views.general],

1 The header <span> defines the view span. The header <mdspan> defines the view basic_mdspan , the type alias mdspan , and other facilities for interacting with these views.

Add the following subclauses to the end of the [views] subclause (after span ):



22.7.� Header <mdspan> synopsis [mdspan.syn]

namespace std { std // [mdspan.extents], class template extents template < ptrdiff_t ... Extents > Extents class extents; extents; // [mdspan.layout], Layout mapping policies class layout_left; layout_left; class layout_right; layout_right; class layout_stride; layout_stride; // [mdspan.accessor.basic] template < class ElementType > ElementType class accessor_basic; accessor_basic; // [mdspan.basic], class template mdspan template < class ElementType, class Extents, class LayoutPolicy = layout_right, ElementType,Extents,LayoutPolicylayout_right, class AccessorPolicy = accessor_basic < ElementType >> AccessorPolicyaccessor_basicElementType class basic_mdspan; basic_mdspan; template < class T, ptrdiff_t ... Extents > T,Extents using mdspan = basic_mdspan < T, extents < Extents ...>> ; mdspanbasic_mdspanT, extentsExtents // [mdspan.extents.compare], extents comparison operators template < ptrdiff_t ... LHS, ptrdiff_t ... RHS > LHS,RHS constexpr bool operator ==( const extents < LHS ...>& , extentsLHS const extents < RHS ...>&) noexcept ; extentsRHS template < ptrdiff_t ... LHS, ptrdiff_t ... RHS > LHS,RHS constexpr bool operator !=( const extents < LHS ...>& , extentsLHS const extents < RHS ...>&) noexcept extentsRHS { return !( lhs == rhs ) ; } lhsrhs template < class ElementType, class Extents, class LayoutPolicy, ElementType,Extents,LayoutPolicy, class AccessorPolicy, class ... SliceSpecifiers > AccessorPolicy,SliceSpecifiers < see below > subspan ( const basic_mdspan < ElementType, basic_mdspansee belowsubspanbasic_mdspanElementType, >& , Extents, LayoutPolicy, AccessorPolicy ...) noexcept ; SliceSpecifiers // tag supporting subspan struct all_type { explicit all_type () = default ; } ; all_typeall_type inline constexpr all_type all = all_type {} ; all_type allall_type }

22.7.� Overview [mdspan.overview]

1 A multidimensional index space is a Cartesian product of integer intervals. Each interval can be represented by a half-open range [I b , I e ), where I b and I e are the lower and upper bounds of the ith dimension. The rank of a multidimensional index space is the number of intervals it represents.

2 A multidimensional index is an element within the a multidimensional index space and can be represented as a pack of integer types. The multidimensional index idx... refers to an element within the domain of a multidimensional index space if both the following are true:

(2.1) sizeof...(idx) is equal to rank, and

(2.2) For all i in the range [0,rank), the ith value of idx is in the range [I b , I e ).

3 For the following subsections, let r be a value in the range [0,rank).

22.7.� Class template extents [mdspan.extents]

22.7.�.1 Overview [mdspan.extents.syn]

namespace std { std template < ptrdiff_t ... Extents > Extents class extents { extents public : using index_type = ptrdiff_t ; index_type // [mdspan.extents.cons], Constructors and assignment constexpr extents () noexcept = default ; extents constexpr extents ( const extents &) noexcept = default ; extentsextents constexpr extents & operator =( const extents &) noexcept = default ; extentsextents template < ptrdiff_t ... OtherExtents > OtherExtents constexpr extents ( const extents < OtherExtents ...>&) noexcept ; extentsextentsOtherExtents template < class ... IndexType > IndexType constexpr extents ( IndexType ...) noexcept ; extentsIndexType template < class IndexType > IndexType constexpr extents ( const array < IndexType, rank_dynamic ()>&) noexcept ; extentsarrayIndexType, rank_dynamic template < ptrdiff_t ... OtherExtents > OtherExtents constexpr extents & operator =( const extents < OtherExtents ...>&) noexcept ; extentsextentsOtherExtents // [mdspan.extents.obs], Observers of the domain multidimensional index space static constexpr size_t rank () noexcept { return sizeof ...( Extents ) ; } rankExtents static constexpr size_t rank_dynamic () noexcept rank_dynamic { return ( size_t ( Extents == dynamic_extent ) + ...) ; } Extentsdynamic_extent static constexpr index_type static_extent ( size_t ) noexcept index_type static_extent { return rank () - rank_dynamic () ; } rankrank_dynamic constexpr index_type extent ( size_t ) const noexcept ; index_type extent private : static constexpr size_t dynamic_index ( size_t ) noexcept ; // exposition only dynamic_index < index_type, rank_dynamic ()> dynamic_extents_ {} ; // exposition only arrayindex_type, rank_dynamicdynamic_extents_ } ; }

22.7.�.2 Overview [mdspan.extents.overview]

1 The class template extents represents a multidimensional index space of of rank equal to sizeof...(Extents) .

2 For all r, let E r be the value of the rth parameter in the template parameter pack Extents . Each E r shall either be a non-negative integer or dynamic_extent , otherwise, the program is ill-formed.

3 E r is a dymnamic extent if it is equal to dynamic_extent , otherwise E r is a static extent. For each E r equivalent to dynamic_extent ,

the upper bound of the interval is stored in the exposition only array dynamic_extents_ at dynamic_extents_[dynamic_index( r )] .

4 If E r is a dynamic extent, let D r be the value of dynamic_extents_[dynamic_index( r )] . The rth interval of an extents is as follows:

(4.1) [0, E r ) if E r is a static extent,

(4.2) otherwise [0, D r ).

constexpr size_t dynamic_index ( size_t i ) noexcept ; // exposition only dynamic_index

5 i <= sizeof...(Extents) is true , returns the number of arguments before the i th template parameter in the template parameter pack Extents equivalent to dynamic_extent . Otherwise, returns rank_dynamic() .

22.7.�.3 Constructors and assignment [mdspan.extents.cons]

template < ptrdiff_t ... OtherExtents > OtherExtents constexpr extents ( const extents < OtherExtents ...>& other ) noexcept ; extentsextentsOtherExtentsother

1 Constraints: (1.1) sizeof...(OtherExtents) equals rank() . (1.2) For all r where static_extent(r) != dynamic_extent and other.static_extent(r) != dynamic_extent are both true , static_extent(r) == other.static_extent(r) is true .

2 Expects: For all r static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true .

3 Effects: For each r where static_extent(r) == dynamic_extent is true , assigns other.extent(r) to dynamic_extent[dynamic_index(r)] .





template < class ... IndexType > IndexType constexpr extents ( IndexType ... dynamic ) noexcept ; extentsIndexTypedynamic

4 Constraints: (4.1) (is_convertible_v<IndexType, index_type> && ...) is true , and (4.2) sizeof...(IndexType) == rank_dynamic() is true .

5 Expects: ((dynamic >= 0) && ...) is true .

6 Effects: Initializes dynamic_extents_ with dynamic... .

template < class IndexType > IndexType constexpr extents ( const array < IndexType, rank_dynamic ()> & dynamic ) noexcept ; extentsarrayIndexType, rank_dynamicdynamic

7 Constraints: is_convertible_v<IndexType, index_type> is true .

8 Expects: dynamic[i] >= 0 is true for all i in the range [0, rank_dynamic()) .

9 Effects: Initializes dynamic_extents_ with dynamic .

template < ptrdiff_t ... OtherExtents > OtherExtents constexpr extents & operator =( const extents < OtherExtents ...>& other ) noexcept ; extentsextentsOtherExtentsother

10 Constraints: (10.1) sizeof...(OtherExtents) equals rank() . (10.2) For all r where static_extent(r) != dynamic_extent and other.static_extent(r) != dynamic_extent are both true , static_extent(r) == other.static_extent(r) is true .

11 Expects: For all r static_extent(r) == dynamic_extent || static_extent(r) == other.extent(r) is true .

12 Effects: For each r where static_extent(r) == dynamic_extent is true , assigns other.extent(r) to dynamic_extent[dynamic_index(r)] .

13 Returns: *this .



22.7.�.3 Observers of the domain multidimensional index space [mdspan.extents.obs]

constexpr index_type extent ( size_t i ) const noexcept ; index_type extent

1 Expects: i < rank() is true .

2 Returns: dynamic_extents_[dynamic_index(i)] if static_extent(i) == dynamic_extent is true , otherwise static_extent(i) .



22.7.�.4 extents comparison operators [mdspan.extents.compare]

template < ptrdiff_t ... LHS, ptrdiff_t ... RHS > LHS,RHS constexpr bool operator ==( const extents < LHS ...>& lhs, const extents < RHS ...>& rhs ) noexcept ; extentsLHSlhs,extentsRHSrhs

1 lhs.rank() equals rhs.rank() and lhs.extents(r) equals rhs.extents(r) for all r , otherwise false .





22.7.� Layout mapping policy [mdspan.layout]

22.7.�.1 Layout mapping requirements [mdspan.layout.reqs]

A layout mapping policy is a class that contains a layout mapping, a nested class template. A layout mapping policy and its layout mapping nested class template meet the requirements in Table �. A layout mapping meets the requirements of Cpp17DefaultConstructible, Cpp17CopyAssignable, and Cpp17EqualityComparable. In Table �: MP denotes a layout mapping policy.

denotes a layout mapping policy. M denotes a specialization of the layout mapping policy’s nested layout mapping template class.

denotes a specialization of the layout mapping policy’s nested layout mapping template class. E denotes a specialization of extents .

denotes a specialization of . e denotes an object of type E .

denotes an object of type . m denotes an object of type M .

denotes an object of type . i... and j... are multidimensional indices in the multidimensional index space defined by e .

and are multidimensional indices in the multidimensional index space defined by . r is an integral value in the range [0, e.rank()) .

is an integral value in the range . dr... is an integer pack where sizeof...(dr) == e.rank() is true and the r th element is equal to 1 and all other elements are 0 .

Expression Return Type Returns Expects MP::template mapping<E> M m.extents() E Returns: e . m(i...) E::index_type Returns: A value in the range of [0, requried_span_size() ) defined by applying the layout mapping to a multidimensional index i... . Expects:

0 ≤ array{i...}[r] < extents().extent(r) for all r in the range [0, Extents::rank() ) . m.required_span_size() E::index_type Returns: If the multidimensional index space that e defines is empty, then zero, else 1 plus the maximum value of m(i...) for all i... in e . m.is_unique() bool Returns: true if for every i... and j... where i != j || ... is true , m(i...) != m(j...) is true . m.is_contiguous() bool Returns: true if for all k in the range [0, m.required_span_size() ) there exists an i... such that m(i...) equals k , otherwise false . m.is_strided() bool Returns: true if for every r there exists an integer sr such that, for all j... and i... in e , where j... equals (i+dr)... m(j...) - m(i...) equals sr . Otherwise, false . M::is_always_unique() bool Returns: true if m.is_unique() is true for any object of type M . M::is_always_contiguous() bool Returns: true if m.is_contiguous() is true for any object of type M . M::is_always_strided() bool Returns: true if m.is_strided() is true for any object of type M . m.stride(r) E::index_type Returns: sr as defined in m.is_strided() above. Expects: m.is_strided() is true .

Table � — Layout mapping policy and layout mapping requirements



22.7.�.2 Class template layout_left [mdspan.layout.left]

1 layout_left meets the requirements of layout mapping policy.

2 layout_left gives a layout mapping where the left-most extent is stride one and strides increase left-to-right as the product of extents.

3 If Extents is not a (possibly cv-qualified) specialization of extents , then the program is ill-formed.

namespace std { std struct layout_left { layout_left template < class Extents > Extents class mapping { mapping using index_type = typename Extents :: index_type; // exposition only index_typeExtentsindex_type; public : constexpr mapping () noexcept = default ; mapping constexpr mapping ( const mapping &) noexcept = default ; mappingmapping constexpr mapping ( const Extents &) noexcept ; mappingExtents template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents constexpr mapping & operator =( const mapping &) noexcept = default ; mappingmapping template < class OtherExtents > OtherExtents constexpr mapping & operator =( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents constexpr Extents extents () const noexcept { return extents_; } Extents extentsextents_; constexpr index_type required_span_size () const noexcept ; index_type required_span_size template < class ... Indices > Indices operator ()( Indices ...) const noexcept ; index_typeIndices static constexpr bool is_always_unique () noexcept { return true ; } is_always_unique static constexpr bool is_always_contiguous () noexcept { return true ; } is_always_contiguous static constexpr bool is_always_strided () noexcept { return true ; } is_always_strided constexpr bool is_unique () const noexcept { return true ; } is_unique constexpr bool is_contiguous () const noexcept { return true ; } is_contiguous constexpr bool is_strided () const noexcept { return true ; } is_strided ( size_t ) const noexcept ; index_type stride template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >&) const noexcept ; mappingOtherExtents template < class OtherExtents > OtherExtents constexpr bool operator !=( const mapping < OtherExtents >& rhs ) const noexcept mappingOtherExtentsrhs { return !(* this == rhs ) ; } rhs private : {} ; // exposition only Extents extents_ } ; } ; }

22.7.�.2.1 layout_left::mapping members [mdspan.layout.layout_left]

constexpr mapping ( const Extents & e ) noexcept ; mappingExtents

1 extents_ with e .

template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

2 Constraints: is_convertible_v<OtherExtents,Extents> is true .

3 Effects: Initializes extents_ with other.extents() .

template < class OtherExtents > OtherExtents constexpr mapping & operator =( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

4 Effects: Equivalent to: = other . extents () ; extents_otherextents return * this ;

() const noexcept ; index_type required_span_size

5 extents().extent(r) for all r in the range [0, Extents::rank() ) .

template < class ... Indices > Indices operator ()( Indices ... i ) const noexcept ; index_typeIndices

6 Constraints: (6.1) sizeof...(Indices) == Extents::rank() is true , and (6.1) (is_convertible_v<Indices, index_type> && ...) is true .

7 Expects: 0 ≤ array{i...}[r] < extents().extent(r) for all r in the range [0, Extents::rank() ).

8 Effects: Let P... be the parameter pack such that is_same_v<make_index_sequence<index_type, sizeof...(Indices)>, integer_sequence<index_type, P...>> is true .

Equivalent to: return Extents::rank() > 0 ? (i*stride(P()) + ...) : 0;

( size_t r ) const ; index_type stride

9 1 if r equals zero, otherwise, the product of extents().extent(k) for all k in the range [0, r ) .

template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >& other ) const noexcept ; mappingOtherExtentsother

10 return extents() == other.extents(); .



22.7.�.3 Class template layout_right [mdspan.layout.right]

1 layout_right meets the requirements of layout mapping policy.

2 The layout mapping property layout_right gives a layout mapping where the right-most extent is stride one and strides increase right-to-left as the product of extents.

3 If Extents is not a (possibly cv-qualified) specialization of extents , then the program is ill-formed.

namespace std { std struct layout_right { layout_right template < class Extents > Extents class mapping { mapping using index_type = typename Extents :: index_type; // exposition only index_typeExtentsindex_type; public : constexpr mapping () noexcept = default ; mapping constexpr mapping ( const mapping &) noexcept = default ; mappingmapping constexpr mapping ( const Extents &) noexcept ; mappingExtents template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents constexpr mapping & operator =( const mapping &) noexcept = default ; mappingmapping template < class OtherExtents > OtherExtents constexpr mapping & operator =( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents constexpr Extents extents () const noexcept { return extents_; } Extents extentsextents_; constexpr index_type required_span_size () const noexcept ; index_type required_span_size template < class ... Indices > Indices operator ()( Indices ...) const noexcept ; index_typeIndices static constexpr bool is_always_unique () noexcept { return true ; } is_always_unique static constexpr bool is_always_contiguous () noexcept { return true ; } is_always_contiguous static constexpr bool is_always_strided () noexcept { return true ; } is_always_strided constexpr bool is_unique () const noexcept { return true ; } is_unique constexpr bool is_contiguous () const noexcept { return true ; } is_contiguous constexpr bool is_strided () const noexcept { return true ; } is_strided ( size_t ) const noexcept ; index_type stride template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >&) const noexcept ; mappingOtherExtents template < class OtherExtents > OtherExtents constexpr bool operator !=( const mapping < OtherExtents >& rhs ) const noexcept mappingOtherExtentsrhs { return !(* this == rhs ) ; } rhs private : {} ; // exposition only Extents extents_ } ; } ; }

22.7.�.3.1 layout_right::mapping members [mdspan.layout.layout_right]

constexpr mapping ( const Extents & e ) noexcept ; mappingExtents

1 extents_ with e .

template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

2 Constraints: is_convertible_v<OtherExtents,Extents> is true .

3 Effects: Initializes extents_ with other.extents() .

template < class OtherExtents > OtherExtents constexpr mapping & operator =( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

4 Effects: Equivalent to: = other . extents () ; extents_otherextents return * this ;

() const noexcept ; index_type required_span_size

5 extents().extent(r) for all r in the range [0, Extents::rank() ) .

template < class ... Indices > Indices operator ()( Indices ... i ) const noexcept ; index_typeIndices

6 Constraints: (6.1) sizeof...(Indices) == Extents::rank() is true , and (6.1) (is_convertible_v<Indices, index_type> && ...) is true .

7 Expects: 0 ≤ array{i...}[r] < extents().extent(r) for all r in the range [0, Extents::rank() ).

8 Effects: Let P... be the parameter pack such that is_same_v<make_index_sequence<index_type, sizeof...(Indices)>, integer_sequence<index_type, P...>> is true .

Equivalent to: return Extents::rank() > 0 ? (i*stride(P()) + ...) : 0;

( size_t r ) const noexcept ; index_type stride

9 1 if r equals Extents::rank()-1 , otherwise, the product of extents().extent(k) for all k in the range [ r+1 , Extents::rank() ) .

template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >& other ) const noexcept ; mappingOtherExtentsother

10 return extents() == other.extents(); .



22.7.�.4 Class template layout_stride [mdspan.layout.stride]

1 layout_stride meets the requirements of layout mapping policy.

2 The layout mapping property layout_stride gives a layout mapping where the strides are user defined.

3 If Extents is not a (possibly cv-qualified) specialization of extents , then the program is ill-formed.

namespace std { std struct layout_stride { layout_stride template < class Extents > Extents class mapping { mapping using index_type = typename Extents :: index_type; // exposition only index_typeExtentsindex_type; public : constexpr mapping () noexcept = default ; mapping constexpr mapping ( const mapping &) noexcept = default ; mappingmapping constexpr mapping ( const Extents & , mappingExtents const array < index_type, Extents :: rank ()>&) noexcept ; arrayindex_type, Extentsrank template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents & operator =( const mapping &) noexcept = default ; mappingmapping template < class OtherExtents > OtherExtents & operator =( const mapping < OtherExtents >&) noexcept ; mappingmappingOtherExtents constexpr Extents extents () const noexcept { return extents_; } Extents extentsextents_; < typename index_type, Extents :: rank ()> strides () const noexcept arrayindex_type, Extentsrankstrides { return strides_; } strides_; constexpr index_type required_span_size () const noexcept ; index_type required_span_size template < class ... Indices > Indices operator ()( Indices ...) const noexcept ; index_typeIndices static constexpr bool is_always_unique () noexcept { return true ; } is_always_unique static constexpr bool is_always_contiguous () noexcept { return false ; } is_always_contiguous static constexpr bool is_always_strided () noexcept { return true ; } is_always_strided constexpr bool is_unique () const noexcept { return true ; } is_unique constexpr bool is_contiguous () const noexcept ; is_contiguous constexpr bool is_strided () const noexcept { return true ; } is_strided ( size_t ) const noexcept ; index_type stride template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >&) const noexcept ; mappingOtherExtents template < class OtherExtents > OtherExtents constexpr bool operator !=( const mapping < OtherExtents >& rhs ) const noexcept mappingOtherExtentsrhs { return !(* this == rhs ) ; } rhs private : {} ; // exposition only Extents extents_ < index_type, Extents :: rank ()> strides_ {} ; // exposition only arrayindex_type, Extentsrankstrides_ } ; } ; }

22.7.�.4.1 layout_stride::mapping members [mdspan.layout.layout_stride]

constexpr mapping ( const Extents & e, array < index_type, Extents :: rank ()> s ) noexcept ; mappingExtentse, arrayindex_type, Extentsrank

1 Let P be a permutation of the integers 0, ..., Extents::rank()-1 and let p i be the ith element of P.

2 Expects: (2.1) s[i] > 0 is true for all i in the range [0, Extents::rank() ). (2.2) If Extents::rank() is greater than zero, then there exists a permutation P such that s[ p i ] >= s( p i − 1 ]) * e.extent( p i − 1 ) is true for all i in the range [1, Extents::rank() ).

3 Effects: Initializes extents_ with e , and initializes strides_ with s .

template < class OtherExtents > OtherExtents constexpr mapping ( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

4 Constraints: is_convertible_v<OtherExtents,Extents> is true .

5 Effects: Initializes extents_ with other.extents() , and initializes strides_ with other.strides() .

template < class OtherExtents > OtherExtents & operator =( const mapping < OtherExtents >& other ) noexcept ; mappingmappingOtherExtentsother

6 Effects: Equivalent to: = other . extents () ; extents_otherextents return * this ;

() const noexcept ; index_type required_span_size

7 extents().extent(r) * stride(r) for all r in the range [0, Extents::rank() ) .

template < class ... Indices > Indices operator ()( Indices ... i ) const noexcept ; index_typeIndices

8 Constraints: (8.1) sizeof...(Indices) == Extents::rank() is true , and (8.1) (is_convertible_v<Indices, index_type> && ...) is true .

9 Expects: 0 ≤ array{i...}[r] < extents().extent(r) for all r in the range [0, Extents::rank() ).

10 Effects: Let P... be the parameter pack such that is_same_v<make_index_sequence<index_type, sizeof...(Indices)>, integer_sequence<index_type, P...>> is true .

Equivalent to: return Extents::rank() > 0 ? (i*stride(P()) + ...) : 0;

constexpr bool is_contiguous () const noexcept ; is_contiguous

11 Let P be a permutation of the integers 0, ..., Extents::rank()-1 and let p i be the ith element of P.

12Returns: (12.1) true if Extents::ranks() is zero. (12.2) Otherwise, true if there is a permutation P such that min(stride( p i ) equals one for i in the range [0, Extents::rank() ), and stride( p i ) equals stride( p i − 1 ) * extents().extent( p i − 1 ) for i in the range [1, Extents::rank() ). (12.3) Otherwise, false .



template < class OtherExtents > OtherExtents constexpr bool operator ==( const mapping < OtherExtents >& other ) const noexcept ; mappingOtherExtentsother

13 return extents() == other.extents(); .

22.7.� Accessor Policy [mdspan.accessor]

1 An accessor policy defines types and operations by which a contiguous set of objects are accessed.

22.7.�.1 Accessor policy requirements [mdspan.accessor.reqs]

2 An accessor policy defines:

(2.1) a handle to a single element of type element_type ;

(2.2) a handle to a contiguous set of elements of type element_type , accessible through the policy’s access method;

(2.3) conversion of a handle to a contiguous set of elements, to a pointer [conv.array]; and

(2.4) getting a handle to the contiguous subset of elements beginning at an integer offset value.

3 [Note: The type of reference need not be element_type& . The type of pointer need not be element_type* . — end note]

4 An accessor policy meets the requirements of Cpp17DefaultConstructible, Cpp17CopyAssignable, and Cpp17EqualityComparable.

5 In Table �:

(5.1) A denotes an accessor policy.

(5.2) a denotes an object of type A .

(5.3) p denotes an object of type A::pointer .

(5.4) i and j each denote a ptrdiff_t value.

Expression Return Type Requirements A A meets the requirements of Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable. A::element_type A::element_type is required to be a complete object type that is not an abstract class type. A::pointer A::pointer meets the requirements of Cpp17DefaultConstructible, Cpp17CopyConstructible, and Cpp17CopyAssignable. A::reference Constraints: is_convertible_v<A::reference,A::element_type> is true , and if is_const_v<A::element_type> is false then is_assignable_v<A::element_type,A::reference> is true . A::offset_policy Accessor policy for accessing a pointer returned by a.offset(p,i) .



Constraints:

— A::offset_policy meets the requirements of an accessor policy in Table �,

— is_convertible_v<A, A::offset_policy> is true , and

— A::offset_policy can be constructed from a . a.decay(p) A::element_type* Returns: A pointer that references the same location as p . a.access(p, i) A::reference Returns: An object which provides access to the i -th element in the range of elements that starts at p . a.offset(p, i) A::offset_policy::pointer Expects:

— a.decay(p)+i equals A::offset_policy(a).decay(a.offset(p, i)) , and

— A::offset_policy(a).access(a.offset(p, i), j) is valid if a.access(p, i+j) is valid.



Returns: A pointer that references the same location as a.decay(p)+i .

Table �: Accessor policy requirements

22.7.�.2 Class template accessor_basic [mdspan.accessor.basic]

1 accessor_basic meets the requirements of accessor policy.

2 ElementType is required to be a complete object type that is neither an abstract class type nor an array type.

namespace std { std template < class ElementType > ElementType struct accessor_basic { accessor_basic using offset_policy = accessor_basic; offset_policyaccessor_basic; using element_type = ElementType; element_typeElementType; using reference = ElementType & ; referenceElementType using pointer = ElementType * ; pointerElementType constexpr typename offset_policy :: pointer offset_policypointer ( pointer p, ptrdiff_t i ) const noexcept ; offsetpointer p, constexpr reference access ( pointer p, ptrdiff_t i ) const noexcept ; reference accesspointer p, constexpr pointer decay ( pointer p ) const noexcept ; pointer decaypointer p } ; }

22.7.�.2 Class template accessor_basic members [mdspan.accessor.members]

constexpr typename offset_policy :: pointer offset_policypointer ( pointer p, ptrdiff_t i ) const noexcept ; offsetpointer p,

1 Expects: p + i is dereferenceable.

2 Returns: p + i .

constexpr reference access ( pointer p, ptrdiff_t i ) const noexcept ; reference accesspointer p,

3 Expects: p + i is dereferenceable.

4 Returns: p[i] .

constexpr pointer decay ( pointer p ) const noexcept ; pointer decaypointer p

5 p .

22.7.� Class template basic_mdspan [mdspan.basic]



22.7.�.1 basic_mdspan overview [mdspan.basic.overview]

1 basic_mdspan maps a multidimensional index in its domain to a reference to an element in its codomain span .

2 The domain of a basic_mdspan object is a multidimensional index space defined by an extents .

3 The codomain of a basic_mdspan object is a span of elements.

4 As with span , the storage of the objects in the codomain span of a basic_mdspan is owned by some other object.

namespace std { std template < class ElementType, class Extents, class LayoutPolicy, class AccessorPolicy > ElementType,Extents,LayoutPolicy,AccessorPolicy class basic_mdspan { basic_mdspan public : // Domain and codomain types using extents_type = Extents; extents_typeExtents; using layout_type = LayoutPolicy; layout_typeLayoutPolicy; using accessor_type = AccessorPolicy; accessor_typeAccessorPolicy; using mapping_type = typename layout_type :: template mapping_type < extents_type > ; mapping_typelayout_typemapping_typeextents_type using element_type = typename accessor_type :: element_type; element_typeaccessor_typeelement_type; using value_type = remove_cv_t < element_type > ; value_typeremove_cv_telement_type using index_type = ptrdiff_t ; index_type using difference_type = ptrdiff_t ; difference_type using pointer = typename accessor_type :: pointer; pointeraccessor_typepointer; using reference = typename accessor_type :: reference; referenceaccessor_typereference; // [mdspan.basic.cons], basic_mdspan constructors, assignment, and destructor constexpr basic_mdspan () noexcept = default ; basic_mdspan constexpr basic_mdspan ( const basic_mdspan &) noexcept = default ; basic_mdspanbasic_mdspan constexpr basic_mdspan ( basic_mdspan &&) noexcept = default ; basic_mdspanbasic_mdspan template < class ... IndexType > IndexType explicit constexpr basic_mdspan ( pointer p, IndexType ... dynamic_extents ) ; basic_mdspanpointer p, IndexTypedynamic_extents template < class IndexType, size_t N > IndexType, explicit constexpr basic_mdspan ( pointer p, const array < IndexType, N >& dynamic_extents ) ; basic_mdspanpointer p,arrayIndexType, Ndynamic_extents constexpr basic_mdspan ( pointer p, const mapping_type & m ) ; basic_mdspanpointer p,mapping_type constexpr basic_mdspan ( pointer p, const mapping_type & m, const accessor_type & a ) ; basic_mdspanpointer p,mapping_typem,accessor_type template < class OtherElementType, class OtherExtents, class OtherLayoutPolicy, class OtherAccessorPolicy > OtherElementType,OtherExtents,OtherLayoutPolicy,OtherAccessorPolicy constexpr basic_mdspan ( const basic_mdspan < OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorPolicy >& other ) ; basic_mdspanbasic_mdspanOtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorPolicyother constexpr basic_mdspan & operator =( const basic_mdspan &) noexcept = default ; basic_mdspanbasic_mdspan constexpr basic_mdspan & operator =( basic_mdspan &&) noexcept = default ; basic_mdspanbasic_mdspan template < class OtherElementType, class OtherExtents, class OtherLayoutPolicy, class OtherAccessorPolicy > OtherElementType,OtherExtents,OtherLayoutPolicy,OtherAccessorPolicy constexpr basic_mdspan & operator =( const basic_mdspan < OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorPolicy >& other ) noexcept ; basic_mdspanbasic_mdspanOtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorPolicyother // [mdspan.basic.mapping], basic_mdspan mapping domain multidimensional index to access codomain element constexpr reference operator []( index_type ) const noexcept ; referenceindex_type template < class ... IndexType > IndexType constexpr reference operator ()( IndexType ... indices ) const noexcept ; referenceIndexTypeindices template < class IndexType, size_t N > IndexType, constexpr reference operator ()( const array < IndexType, N >& indices ) const noexcept ; referencearrayIndexType, Nindices () const { return acc_; } accessor_type accessoracc_; static constexpr int rank () noexcept { return Extents :: rank () ; } rankExtentsrank static constexpr int rank_dynamic () noexcept { return Extents :: rank_dynamic () ; } rank_dynamicExtentsrank_dynamic static constexpr index_type static_extent ( size_t r ) noexcept { return Extents :: static_extent ( r ) ; } index_type static_extentExtentsstatic_extent constexpr Extents extents () const noexcept { return map_ . extents () ; } Extents extentsmap_extents constexpr index_type extent ( size_t r ) const noexcept { return extents (). extent ( r ) ; } index_type extentextentsextent constexpr index_type size () const noexcept ; index_type size constexpr index_type unique_size () const noexcept ; index_type unique_size // [mdspan.basic.codomain], basic_mdspan observers of the codomain constexpr span < element_type > span () const noexcept ; spanelement_typespan constexpr pointer data () const noexcept { return ptr_; } pointer dataptr_; static constexpr bool is_always_unique () noexcept { return mapping_type :: is_always_unique () ; } is_always_uniquemapping_typeis_always_unique static constexpr bool is_always_contiguous () noexcept { return mapping_type :: is_always_contiguous () ; } is_always_contiguousmapping_typeis_always_contiguous static constexpr bool is_always_strided () noexcept { return mapping_type :: is_always_strided () ; } is_always_stridedmapping_typeis_always_strided constexpr mapping_type mapping () const noexcept { return map_; } mapping_type mappingmap_; constexpr bool is_unique () const noexcept { return map_ . is_unique () ; } is_uniquemap_is_unique constexpr bool is_contiguous () const noexcept { return map_ . is_contiguous () ; } is_contiguousmap_is_contiguous constexpr bool is_strided () const noexcept { return map_ . is_strided () ; } is_stridedmap_is_strided constexpr index_type stride ( size_t r ) const { return map_ . stride ( r ) ; } index_type stridemap_stride private : {} ; // exposition only accessor_type acc_ {} ; // exposition only mapping_type map_ {} ; // exposition only pointer ptr_ } ; }

5 ElementType is required to be a complete object type that is neither an abstract class type nor an array type.

6 If Extents is not a (cv-unqualified) specialization of extents , then the program is ill-formed.

7 If LayoutPolicy does not meet the layout mapping policy requirements, then the program is ill-formed.

8 If AccessorPolicy does not meet the accessor policy requirements or if std::is_same_v<typename AccessorPolicy::element_type,ElementType> is false , then the program is ill-formed.

22.7.�.1 basic_mdspan constructors and assignment operators [mdspan.basic.cons]

template < class ... IndexType > IndexType explicit constexpr basic_mdspan ( pointer ptr, IndexType ... dynamic_extents ) ; basic_mdspanpointer ptr, IndexTypedynamic_extents

1 Constraints: (1.1) (is_convertible_v<IndexType, index_type> && ...) is true , (1.2) sizeof...(dynamic_extents) == rank_dynamic() is true , (1.3) is_constructible_v<mapping_type, Extents> is true , and (1.4) is_default_constructible_v<accessor_type> is true .

2 Effects: (2.1) Initializes ptr_ with ptr , (2.2) Initializes map_ with Extents(dynamic_extents...) , and

3 Throws: Nothing.

template < class IndexType, size_t N > IndexType, explicit constexpr basic_mdspan ( pointer p, const array < IndexType, N >& dynamic_extents ) ; basic_mdspanpointer p,arrayIndexType, Ndynamic_extents

4 Constraints: (4.1) is_convertible_v<IndexType, index_type> is true , (4.2) N == rank_dynamic() is true , (4.3) is_constructible_v<mapping_type, Extents> is true , and (4.4) is_default_constructible_v<accessor_type> is true .

5 Effects: Equivalent to: basic_mdspan(p, dynamic_extents[Rs]...) , with Rs... from index_sequence<Rs...> matching make_index_sequence<N> .

6 Throws: Nothing.

constexpr basic_mdspan ( pointer p, const mapping_type & m ) ; basic_mdspanpointer p,mapping_type

7 Constraints: is_default_constructible_v<accessor_type> is true .

8 Effects: (8.1) Initializes ptr_ with p , (8.2) Initializes map_ with m , and

9 Throws: Nothing.

constexpr basic_mdspan ( pointer p, const mapping_type & m, const accessor_type & a ) ; basic_mdspanpointer p,mapping_typem,accessor_type

10Effects: (10.1) Initializes ptr_ with p , (10.2) Initializes map_ with m , and (10.3) Initializes acc_ with a .

11 Throws: Nothing.

template < class OtherElementType, class OtherExtents, class OtherLayoutPolicy, class OtherAccessor > OtherElementType,OtherExtents,OtherLayoutPolicy,OtherAccessor constexpr basic_mdspan ( const basic_mdspan < OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessor >& other ) ; basic_mdspanbasic_mdspanOtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorother

12 Constraints: (12.1) is_convertible_v<OtherLayoutPolicy::template mapping<OtherExtents>, mapping_type is true ; (12.2) is_convertible_v<OtherAccessor, Accessor> is true ; (12.3) is_convertible_v<OtherAccessor::pointer, pointer> is true ; (12.4) is_convertible_v<OtherExtents, extents_type> is true ; and (12.5) For all r in the range [0, rank()) , if other.static_extent(r) != dynamic_extent && static_extent(r) != dynamic_extent is true , then other.static_extent(r) == static_extent(r) is true .

13 Expects: For all r in the range [0, rank()) , if other.static_extent(r) == dynamic_extent || static_extent(r) == dynamic_extent is true , then other.extent(r) == extent(r) is true .

14 Effects: (14.1) Initializes ptr_ with other.ptr_ , (14.2) initializes map_ with other.map_ , and (14.3) initializes acc_ with other.acc_ .

15 Throws: Nothing.

template < class OtherElementType, class OtherExtents, class OtherLayoutPolicy, class OtherAccessor > OtherElementType,OtherExtents,OtherLayoutPolicy,OtherAccessor constexpr basic_mdspan & operator =( const basic_mdspan < OtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessor >& other ) ; basic_mdspanbasic_mdspanOtherElementType, OtherExtents, OtherLayoutPolicy, OtherAccessorother

16 Constraints: (16.1) is_assignable_v<mapping_type, OtherLayoutPolicy::template mapping<OtherExtents>> is true ; (16.2) is_assignable_v<Accessor, OtherAccessor> is true ; (16.3) is_assignable_v<pointer, OtherAccessor::pointer> is true ; (16.4) OtherExtents::rank() == rank() is true ; and (16.5) For all r in the range [0, rank()) , if other.static_extent(r) != dynamic_extent && static_extent(r) != dynamic_extent is true , then other.static_extent(r) == static_extent(r) is true .

17 Expects: For all r in the range [0, rank()) , if other.static_extent(r) == dynamic_extent || static_extent(r) == dynamic_extent is true , then other.extent(r) == extent(r) is true .

18 Effects: (18.1) Assigns other.ptr_ to ptr_ , (18.2) Assigns other.map_ to map_ , and (18.3) Assigns other.acc_ to acc_ .

17 Throws: Nothing.



22.7.�.2 basic_mdspan members [mdspan.basic.members]

constexpr reference operator []( index_type i ) const ; referenceindex_type i

1 Constraints: rank() == 1 is true .

2 Expects: acc_.access(ptr_, map_(i)) shall be valid.

3 Effects: Equivalent to: return (*this)(i); .





template < class ... IndexType > IndexType constexpr reference operator ()( IndexType ... indices ) const ; referenceIndexTypeindices

4 Constraints: (4.1) (is_convertible_v<IndexType, index_type> && ...) is true , and (4.2) sizeof...(IndexType) == rank() is true .

5 Expects: acc_.access(ptr_, map_(indices...)) shall be valid.

6 Effects: Equivalent to: return acc_.access(ptr_, map_(indices...)); .

7 Throws: Nothing.

template < class IndexType, size_t N > IndexType, constexpr reference operator ()( const array < IndexType, N >& indices ) const ; referencearrayIndexType, Nindices

8 Constraints: (8.1) is_convertible_v<IndexType, index_type> is true , and (8.2) rank() == N is true .

9 Effects: Equivalent to: return std::apply(*this, indices); .

10 Throws: nothing.

constexpr index_type size () const noexcept ; index_type size

11 extent(r) for all r in the range [0, Extents::rank()) .

constexpr index_type unique_size () const noexcept ; index_type unique_size

12 mapping().is_unique() is true , this is identical to size() . _—end note]

constexpr span < element_type > span () const noexcept ; spanelement_typespan

13 return span<element_type>(acc_.decay(ptr_), required_span_size()); .

22.7.� subspan [mdspan.subspan]

1 subspan creates a basic_mdspan with a domain that is a subset of the input basic_mdspan ’s domain, and a codomain that is a subset of the input basic_mdspan ’s codomain.

2 The SliceSpecifier template argument(s) and the corresponding value(s) of the arguments of subspan after src determine the subset of src that the basic_mdspan returned by subspan views.

namespace std { std // [mdspan.subspan], subspan creation template < class ElementType, class Extents, class LayoutPolicy, ElementType,Extents,LayoutPolicy, class AccessorPolicy, class ... SliceSpecifiers > AccessorPolicy,SliceSpecifiers < see below > basic_mdspansee below ( const basic_mdspan < ElementType, Extents, LayoutPolicy, subspanbasic_mdspanElementType, Extents, LayoutPolicy, >& src, SliceSpecifiers ... slices ) noexcept ; AccessorPolicysrc, SliceSpecifiersslices }

3 Let sub be the return value of subspan(src, slices...) , let s k be the k-th element of slices... , and let S k be the type of the k-th element of slices... .

4 Define map_rank as an array<ptrdiff_t,src.rank()> such that map_rank[j] equals -1 if is_convertible_v< S j ,ptrdiff_t> is true , or else map_rank[j] equals the number of S k with k < j such that is_convertible_v< S k ,pair<ptrdiff_t,ptrdiff_t>> || is_convertible_v< S k ,all_type> is true .

5 Let first and last be exposition-only variables of type array<ptrdiff_t,src.rank()> . For r in the range [0, src.rank() ), define the values of first[r] and last[r] as follows:

if is_convertible_v< S r ,ptrdiff_t> , then first[r] equals s r , and last[r] equals first[r] + 1;

, then equals , and equals + 1; otherwise, if is_convertible_v< S r ,pair<ptrdiff_t,ptrdiff_t>> , then first[r] equals p.first , and last[r] equals p.second , where p is the result of converting s r to pair<ptrdiff_t,ptrdiff_t> ;

, then equals , and equals , where is the result of converting to ; otherwise, if is_convertible_v< S r ,all_type> , then first[r] equals 0 , and last[r] equals src.extent(r) .

6 Constraints:

sizeof(slices...) equals src.rank() ,

equals , LayoutPolicy is layout_left , layout_right , layout_stride , or any type in a possibly empty set of implementation-defined types, each of which meets the requirements of a layout mapping policy [mdspan.layout.reqs] [Note:* Implementation and user defined layout mapping policies could exist, for which taking an arbitrary subspan does not make sense. *— end note]; and

is , , , or any type in a possibly empty set of implementation-defined types, each of which meets the requirements of a layout mapping policy [Note:* Implementation and user defined layout mapping policies could exist, for which taking an arbitrary does not make sense. *— end note]; and For all k in the range [0, src.rank()) , is_convertible_v< S k ,ptrdiff_t> || is_convertible_v< S k ,pair<ptrdiff_t,ptrdiff_t>> || is_convertible_v< S k ,all_type> is true .

7 Expects:

For 0 ≤ r < src.rank() , 0 <= first[r] && first[r] <= last[r] && last[r] <= src.extent(r) is true .

8 Ensures: All of the following:

sub.rank() equals the number of k such that is_convertible_v< S k ,pair<ptrdiff_t,ptrdiff_t>> || is_convertible_v< S k ,all_type> is true .

equals the number of such that is . Let the pack i... denote a multidimensional index in the domain of src with i k denoting the k -th element of i... , such that i k is greater than or equal to first[k] and i k is less than last[k] for all k in the range [0, src.rank() ) . Let the pack j... denote a multidimensional index in the domain of sub with j s denoting the s -th element of j... , such that j s is equal to i k minus first[k] where map_rank[k] equals s for all s in the range [0, sub.rank() ) . Then sub(j...) and src(i...) refer to the same element in the codomain of src .

denote a multidimensional index in the domain of with denoting the -th element of , such that is greater than or equal to and is less than for all in the range . Let the pack denote a multidimensional index in the domain of with denoting the -th element of , such that is equal to minus where equals for all in the range . Then and refer to the same element in the codomain of . For 0 ≤ k < src.rank() , if map_rank[k] != -1 is true , then sub.extent(map_rank[k]) equals last[k] - first[k] .

< , if is , then equals . If src.is_strided() is true , then sub.is_strided() is true , and for all k in the range [0, src.rank()) , if map_rank[k] != -1 is true , then sub.stride(map_rank[k]) equals src.stride(k) .

is , then is , and for all in the range , if is , then equals . For all k in the range [0, src.rank()) , if map_rank[k] != -1 is true and src.static_extent(k) does not equal dynamic_extent and is_convertible_v< S k ,all_type> is true , then sub.static_extent(map_rank[k]) equals src.static_extent(k) .





[Note: Example of subspan use:

// Create a mapping typedef extents < 3 ,dynamic_extent, 7 > Extents3D; extents,dynamic_extent,Extents3D; :: template mapping < Extents3D > map_right ( 10 ) ; layout_rightmappingExtents3Dmap_right // Allocate a basic_mdspan int * ptr = new int [ 3 * 8 * 10 ] ; ptr < int ,Extents3D,layout_right > a ( ptr,map_right ) ; basic_mdspan,Extents3D,layout_rightptr,map_right // Initialize the span for ( int i0 = 0 ; i0 < a . extent ( 0 ) ; i0 ++) i0; i0extent; i0 for ( int i1 = 0 ; i1 < a . extent ( 1 ) ; i1 ++) i1; i1extent; i1 for ( int i2 = 0 ; i2 < a . extent ( 2 ) ; i2 ++) i2; i2extent; i2 a ( i0,i1,i2 ) = 10000 * i0 + 100 * i1 + i2; i0,i1,i2i0i1i2; // Create Subspan auto a_sub = subspan ( a, 1 ,std :: pair < int , int >( 4 , 6 ) ,std :: pair < int , int >( 1 , 6 )) ; a_subsubspana,,stdpair,stdpair // Print values of subspan for ( int i0 = 0 ; i0 < a_sub . extent ( 0 ) ; i0 ++) { i0; i0a_subextent; i0 for ( int i1 = 0 ; i1 < a_sub . extent ( 1 ) ; i1 ++) { i1; i1a_subextent; i1 :: cout << a_sub ( i0,i1 ) << " " ; stdcouta_subi0,i1 } :: cout << std :: endl; stdcoutstdendl; } /* Output 10401 10402 10403 10404 10405 10501 10502 10503 10504 10505 */

- end note]

5 Next Steps

Wording editing as per guidance from LWG.

6 Related Work

LEWG issue

Previous paper:

[[N4355]]

P0860 : Access Policy Generating Proxy Reference

The reference type may be a proxy for accessing an element_type object. For example, the atomic AccessorPolicy in P0860 defines AccessorPolicy::template accessor_type<T>::reference to be atomic_ref<T> from P0019.

Related papers: