kokkos / kokkos/mdspan

LEWG 2026/02/10: PL-007, P3982R0

Open
#448 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
507
Forks
87
Avg merge
15h 27m
Merged PRs (30d)
2

Description

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
  1. input span: range of indices into input, that can be accessed by output
  2. output extent: size of the range of valid indices for output
2 possible choices of meaning for strided_slice's extent
  1. input span $[$ offset, offset + extent $)$, thus output extent is 1 + (extent - 1) / stride
    • STATUS QUO
  2. output extent, thus input span is $[$ offset, 1 + offset + (extent - 1)*stride $)$
    • P3982
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
Image
  • 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
      • Same as input .extent
Image
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:

  1. Permit zero strides in the future (for "broadcasting" layouts)
  2. Enable representing (static extent, dynamic stride)

P3982R0 points out 2 more:

  1. Avoid integer divisions
    • Performance
    • Remove undefined behavior (division by zero stride)
  2. 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.

  1. 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
  2. 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

  1. Accept rename [to extent_slice] and changes to strided_slice class template from P3982R0 to C++26.

  2. Accept the introduction of range_slice class template from P3982R0 to C++26.

  3. Accept any type decomposable into three elements as submdspan slice type as proposed in P3982R0 to C++29.

  4. Accept any type decomposable into three elements as submdspan slice type as proposed in P3982R0 to C++26.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the issue's comparison of strided_slice semantics and the linked P3982R0 paper, then inspect the submdspan canonicalization and mapping interfaces in the repository. The proposed work would require resolving the C++26 design questions around extent_slice, range_slice, and decomposable slice types before implementation and tests can be defined.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
backend-api-design
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.