PL-007 23.7.3.7 [mdspan.sub] Define the extent member of the strided_slice
NB comment: https://github.com/cplusplus/nbballot/issues/816
Paper: https://isocpp.org/files/papers/P3982R0.html
Make strided_slice:::extent define the output extent, not the input span
2 ranges of indices in submdspan
- input span: range of indices into input, that can be accessed by output
- output extent: size of the range of valid indices for output
2 possible choices of meaning for strided_slice's extent
-
input span $[$
offset, offset + extent $)$, thus output extent is 1 + (extent - 1) / stride
-
output extent, thus input span is $[$
offset, 1 + offset + (extent - 1)*stride $)$
Example: status quo vs. P3982R0
Example: strided_slice{.offset = 1, .extent = 10, .stride = 3}.
- Status quo
- View input indices 1, 4, 7, and 10
- Input span: $[1, 1 + 10) = [1, 11)$
- Output extent:
offset + (extent - 1) / stride = 1 + (10 - 1) / 3 = 4
- NOT same as input
.extent 10
- P3982R0
- View input indices 1, 4, 7, 10, 13, 16, 19, 22, 25, 28
- Input span: $[$
offset, offset + 1 + (extent - 1)*stride $)$ = $[1, 29)$
- Output extent: 10
Status quo aimed for minimal change from first : last : stride
- Original
submdspan paper P2630 lacked P3663's notion of "canonical slice types" vs. all slice types
- Thus, P2630 authors defined slice types based on familiarity
- Most familiar syntax: Fortran's and Python's
first : last : stride
- But
first : last : stride can't represent (dynamic offset, static extent, static stride)
- Key case for performance, e.g., unrolled loop
- Status quo in P2630 made the minimal-distance-from-familiarity change to include this case:
- Replace
last with extent = last - first
- Rename
first to offset
Why change status quo?
NB comment points out 2 reasons:
- Permit zero strides in the future (for "broadcasting" layouts)
- Enable representing (static extent, dynamic stride)
P3982R0 points out 2 more:
- Avoid integer divisions
- Performance
- Remove undefined behavior (division by zero stride)
- Less confusing (input "extent" is not output extent; I have to look this up every time)
Another reason: strided_slice is a canonical slice type
- Canonical slice types define interface between
submdspan and a layout mapping's submdspan_mapping
submdspan function body looks like this:
auto [...canonical_slices] =
submdspan_canonicalize_slices(src.extents(), user_slices...);
auto sub_map_result =
submdspan_mapping(src.mapping(), canonical_slices...);
return mdspan(
src.accessor().offset(src.data_handle(), sub_map_result.offset),
sub_map_result.mapping,
typename AccessorPolicy::offset_policy(src.accessor()));
- Choose canonical types to express the biggest possible set of slices
- We can always add new user-facing slices to improve familiarity (see
range_slice below)
Why do we need to change it for C++26?
Changing the meaning of strided_slice::extent later would silently break the meaning of submdspan.
(It would be an ABI break. You don't like those, right?)
Also for C++26: Rename strided_slice to extent_slice
-
Paper proposes a new non-canonical slice type range_slice to cover common use case first : last : stride (Python, Fortran, etc.)
-
Whether that arrives in C++26 or C++29, that would mean there are multiple *_slice types with a stride
-
strided_slice is a canonical slice type; changing name after C++26 would break users' customizations of submdspan_mapping
-
New name: extent_slice, because it has the output extent, not the input span
Additional new features
Paper proposes 2 new features. They could be added for C++26 or in a later Standard.
-
range_slice{.first = first, .last = last, .stride = stride}
- Models slicing in other programming languages
- Calls for renaming
strided_slice TO extent_slice NOW, even if we add range_slice later
range_slice also has a "stride"
- So "
strided_slice" wouldn't be the only "strided" slice
-
Interpret any type for which structured binding auto [first, last, stride] = s; is valid as range_slice
- Only makes sense if we add
range_slice as in (1)
Why add range_slice in C++26?
-
Popular programming languages have first : last : stride slices, so users will demand them
- Fortran:
array(first:last), array(first:last:step)
- Python:
array[first:last], array[first:last:step]
- Matlab:
array(first:last), (annoyingly) array(first:step:last)
-
Designated initializers alleviate order concerns
Why add auto [first, last, stride] = s;?
- Confusion about order (Python vs. Matlab) led the
submdspan (P2630) authors not to include this feature, but
- status quo already interprets
auto [first, last] = s; as stride = cw<1zu>
- so
auto [first, last, stride] = s; is less ambiguous, analogous to a default function parameter stride = cw<1zu>
- Trivial to implement: we already handle
auto [...ts] = t; with sizeof...(ts) == 2
- We consider this optional for C++26
Suggested polls
-
Accept rename [to extent_slice] and changes to strided_slice class template from P3982R0 to C++26.
-
Accept the introduction of range_slice class template from P3982R0 to C++26.
-
Accept any type decomposable into three elements as submdspan slice type as proposed in P3982R0 to C++29.
-
Accept any type decomposable into three elements as submdspan slice type as proposed in P3982R0 to C++26.
PL-007 23.7.3.7 [mdspan.sub] Define the
extentmember of thestrided_sliceNB comment: https://github.com/cplusplus/nbballot/issues/816
Paper: https://isocpp.org/files/papers/P3982R0.html
Make
strided_slice:::extentdefine the output extent, not the input span2 ranges of indices in
submdspan2 possible choices of meaning for
strided_slice'sextentoffset,offset + extent1 + (extent - 1) / strideoffset,1 + offset + (extent - 1)*strideExample: status quo vs. P3982R0
Example:
strided_slice{.offset = 1, .extent = 10, .stride = 3}.offset + (extent - 1) / stride=1 + (10 - 1) / 3= 4.extent10offset,offset + 1 + (extent - 1)*stride.extentStatus quo aimed for minimal change from
first : last : stridesubmdspanpaper P2630 lacked P3663's notion of "canonical slice types" vs. all slice typesfirst : last : stridefirst : last : stridecan't represent (dynamic offset, static extent, static stride)lastwithextent = last - firstfirsttooffsetWhy change status quo?
NB comment points out 2 reasons:
P3982R0 points out 2 more:
Another reason:
strided_sliceis a canonical slice typesubmdspanand a layout mapping'ssubmdspan_mappingsubmdspanfunction body looks like this:range_slicebelow)Why do we need to change it for C++26?
Changing the meaning of
strided_slice::extentlater would silently break the meaning ofsubmdspan.(It would be an ABI break. You don't like those, right?)
Also for C++26: Rename
strided_slicetoextent_slicePaper proposes a new non-canonical slice type
range_sliceto cover common use casefirst : last : stride(Python, Fortran, etc.)Whether that arrives in C++26 or C++29, that would mean there are multiple
*_slicetypes with a stridestrided_sliceis a canonical slice type; changing name after C++26 would break users' customizations ofsubmdspan_mappingNew name:
extent_slice, because it has the output extent, not the input spanAdditional new features
Paper proposes 2 new features. They could be added for C++26 or in a later Standard.
range_slice{.first = first, .last = last, .stride = stride}strided_sliceTOextent_sliceNOW, even if we addrange_slicelaterrange_slicealso has a "stride"strided_slice" wouldn't be the only "strided" sliceInterpret any type for which structured binding
auto [first, last, stride] = s;is valid asrange_slicerange_sliceas in (1)Why add
range_slicein C++26?Popular programming languages have
first : last : strideslices, so users will demand themarray(first:last),array(first:last:step)array[first:last],array[first:last:step]array(first:last), (annoyingly)array(first:step:last)Designated initializers alleviate order concerns
Why add
auto [first, last, stride] = s;?submdspan(P2630) authors not to include this feature, butauto [first, last] = s;asstride = cw<1zu>auto [first, last, stride] = s;is less ambiguous, analogous to a default function parameterstride = cw<1zu>auto [...ts] = t;withsizeof...(ts) == 2Suggested polls
Accept rename [to
extent_slice] and changes tostrided_sliceclass template from P3982R0 to C++26.Accept the introduction of
range_sliceclass template from P3982R0 to C++26.Accept any type decomposable into three elements as
submdspanslice type as proposed in P3982R0 to C++29.Accept any type decomposable into three elements as
submdspanslice type as proposed in P3982R0 to C++26.