From e06ff49fbeb3d345e5b20877c59ab514d16cd2a2 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Thu, 2 Apr 2026 20:36:56 +0200 Subject: [PATCH 1/2] P3982R2 Split strided_slice into extent_slice and range_slice for C++26 (1/2) Fixes NB PL-007 (C++26 CD). --- source/containers.tex | 184 +++++++++++++++++++++++++++++++----------- source/support.tex | 2 +- 2 files changed, 136 insertions(+), 50 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 4aba72d02d..95518dac62 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -21281,6 +21281,8 @@ // \ref{mdspan.sub}, \tcode{submdspan} creation template struct strided_slice; + template> + struct range_slice; template struct submdspan_mapping_result; @@ -25547,7 +25549,13 @@ \tcode{is_convertible_v<$X$, IndexType>} is \tcode{true} for $X$ denoting \tcode{$S$::offset_type}, \tcode{$S$::extent_type}, and - \tcode{$S$::stride_type}; or + \tcode{$S$::stride_type}; +\item + $S$ is a specialization of \tcode{range_slice} and + \tcode{is_convertible_v} is \tcode{true} for $X$ denoting type of + \tcode{$S$::first}, + \tcode{$S$::last}, and + \tcode{$S$::stride} members; or \item all of the following hold: \begin{itemize} @@ -25624,6 +25632,10 @@ \item \range{$0$}{e.extent($k$)}, if \tcode{S} is \tcode{full_extent_t}; +\item + \range{E::index_type(s.offset)}{E::index_type(s.offset)}, + if \tcode{S} is a specialization of \tcode{strided_slice} and + \tcode{E::index_type(s.extent)} is zero; otherwise \item \range{E::index_type(s.offset)}{E::index_type(s.offset + s.extent)}, if \tcode{S} is a specialization of \tcode{stri\-ded_slice}; otherwise @@ -25643,16 +25655,30 @@ if \tcode{S} is a specialization of \tcode{strided_slice}: \begin{itemize} \item - if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper}, - then \tcode{S::offset_type::value} is less than or equal to $x$; + $o$ is less than or equal to $x$; \item - if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper}, - then \tcode{S::extent_type::value} is less than or equal to $x$; and + $e$ is less than or equal to $x$; \item - if both \tcode{S::offset_type} and \tcode{S::extent_type} - are specializations of \tcode{constant_wrapper}, - then \tcode{S::offset_type::value + S::extent_type::value} - is less than or equal to $x$; or + if $e$ is greater than one, + then $t$ is greater than zero, + \item + if $e$ is greater than zero, + then $o + 1 + (e - 1) * t$ is less than or equal to $x$ + \end{itemize} + where + \begin{itemize} + \item + $o$ is value of \tcode{S::offset_type::value} + if \tcode{S::offset_type} is a specialization of \tcode{constant_wrapper} and + \tcode{0} otherwise, + \item + $e$ is value of \tcode{S::extent_type::value} + if \tcode{S::extend_type} is a specialization of \tcode{constant_wrapper} and + \tcode{0} otherwise, + \item + $t$ is value of \tcode{S::stride_type::value} + if \tcode{S::stride_type} is a specialization of \tcode{constant_wrapper} and + \tcode{1} otherwise. \end{itemize} \item if $S$ is a specialization of \tcode{constant_wrapper}, @@ -25677,19 +25703,20 @@ if \tcode{S} is a specialization of \tcode{strided_slice}, then: \begin{itemize} \item \tcode{s.extent} is greater than or equal to zero, and - \item either \tcode{s.extent} equals zero or \tcode{s.stride} is greater than zero. + \item either \tcode{s.extent} is less than two or \tcode{s.stride} is greater than zero. \end{itemize} \end{itemize} -\rSec4[mdspan.sub.strided.slice]{\tcode{strided_slice}} +\rSec4[mdspan.sub.range.slices]{\tcode{Range slices}} \pnum -\tcode{strided_slice} represents a set of +\tcode{strided_slice} and \tcode{range_slice} represent a set of \tcode{extent} regularly spaced integer indices. -The indices start at \tcode{offset}, and +The indices start at \tcode{offset} and \tcode{first} respectively, and increase by increments of \tcode{stride}. \indexlibraryglobal{strided_slice}% +\indexlibraryglobal{range_slice}% \begin{codeblock} namespace std { template @@ -25702,21 +25729,31 @@ [[no_unique_address]] extent_type extent{}; [[no_unique_address]] stride_type stride{}; }; + + template> + struct range_slice { + [[no_unique_address]] FirstType first{}; + [[no_unique_address]] LastType last{}; + [[no_unique_address]] StrideType stride{}; + }; } \end{codeblock} \pnum -\tcode{strided_slice} has the data members and special members specified above. -It has no base classes or members other than those specified. +\tcode{strided_slice} and \tcode{range_slice} +have the data members and special members specified above. +They have no base classes or members other than those specified. \pnum \mandates -\tcode{OffsetType}, \tcode{ExtentType}, and \tcode{StrideType} +\tcode{OffsetType}, \tcode{ExtentType}, +\tcode{FirstType}, \tcode{LastType}, and \tcode{StrideType} are signed or unsigned integer types, or model \exposconcept{integral-constant-like}. \begin{note} -\tcode{strided_slice\{.offset = 1, .extent = 10, .stride = 3\}} -indicates the indices \tcode{1}, \tcode{4}, \tcode{7}, and \tcode{10}. +Both \tcode{strided_slice\{.offset = 1, .extent = 4, .stride = 3\}} and +\tcode{range_slice\{.first = 1, .last = 11, .stride = 3\}} +indicate the indices \tcode{1}, \tcode{4}, \tcode{7}, and \tcode{10}. Indices are selected from the half-open interval \range{1}{1 + 10}. \end{note} @@ -25766,6 +25803,18 @@ if \tcode{T} is a specialization of \tcode{strided_slice}. \end{itemdescr} +\begin{itemdecl} +template + concept @\defexposconcept{is-range-slice}@ = @\seebelow;@ +\end{itemdecl} + +\begin{itemdescr} +\pnum +The concept \tcode{\exposconcept{is-range-slice}} +is satisfied and modeled if and only +if \tcode{T} is a specialization of \tcode{range_slice}. +\end{itemdescr} + \indexlibraryglobal{\exposid{canonical-index}}% \begin{itemdecl} template @@ -25796,6 +25845,53 @@ \end{itemize} \end{itemdescr} +\begin{itemdecl} +template + constexpr auto @\exposid{canonical-range-slice}@(OffsetType offset, SpanType span, StrideTypes... strides); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let: +\begin{itemize} +\item + \tcode{StrideType} denote + \tcode{constant_wrapper} + if \tcode{StrideTypes} is an empty pack or + \tcode{SpanType} denotes \tcode{constant_wrapper}, otherwise + \tcode{StrideTypes...[0]}; +\item + \tcode{stride} be + \tcode{StrideType()} if \tcode{StrideType} + is a specialization of \tcode{constant_wrapper}, otherwise + \tcode{IndexType(1)} if \tcode{span == 0} is \tcode{true}, otherwise + \tcode{strides...[0]}; +\item + \exposid{extent-value} be \tcode{1 + (span - 1) / stride} + if \tcode{span != 0} is \tcode{true}, and + \tcode{0} otherwise; +\item + \tcode{extent} be \tcode{cw} + if both \tcode{SpanType} and \tcode{StrideType} + are specializations of \tcode{constant_wrapper}, and + \tcode{IndexType(\exposid{extent-value})} otherwise. +\end{itemize} + +\pnum +\mandates +\tcode{sizeof...(StrideTypes) <= 1} is \tcode{true}, and +if \tcode{StrideType} is a specialization of \tcode{con\-stant_wrapper}, +then \tcode{StrideType::value > 0} is \tcode{true}. + +\pnum +\expects +\tcode{stride > 0} is \tcode{true}. + +\pnum +\returns +\tcode{strided_slice\{ .offset = offset, .extent = extent, .stride = stride \};} +\end{itemdescr} + \indexlibraryglobal{\exposid{canonical-slice}} \begin{itemdecl} template @@ -25818,28 +25914,25 @@ } else if constexpr (@\exposconcept{is-strided-slice}@) { auto c_extent = @\exposid{canonical-index}@(std::move(s.extent)); auto c_offset = @\exposid{canonical-index}@(std::move(s.offset)); - if constexpr (is_same_v>) { - return strided_slice{ - .offset = c_offset, - .extent = c_extent, - .stride = cw - }; - } else { - return strided_slice{ - .offset = c_offset, - .extent = c_extent, - .stride = @\exposid{canonical-index}@(std::move(s.stride)) - }; - } + return strided_slice{ + .offset = @\exposid{canonical-index}@(std::move(s.extent)), + .extent = @\exposid{canonical-index}@(std::move(s.offset)), + .stride = @\exposid{canonical-index}@(std::move(s.stride)) + }; +} else if constexpr (@\exposid{is-range-slice}@) { + auto c_first = canonical-index(std::move(s.first)); + auto c_last = canonical-index(std::move(s.last)); + return @\exposid{canonical-slice-range}@( + c_first, + @\exposid{canonical-index}@(c_last - c_first), + @\exposid{canonical-index}@(std::move(s.stride))); } else { auto [s_first, s_last] = std::move(s); auto c_first = @\exposid{canonical-index}@(std::move(s_first)); auto c_last = @\exposid{canonical-index}@(std::move(s_last)); - return strided_slice{ - .offset = c_first, - .extent = @\exposid{canonical-index}@(c_last - c_first), - .stride = cw - }; + return @\exposid{canonical-slice-range}@( + c_first, + @\exposid{canonical-index}@(c_last - c_first)); } \end{codeblock} \end{itemdescr} @@ -25929,7 +26022,7 @@ \tcode{\placeholder{MAP_RANK}(slices, Extents::rank())}; and \item -for each rank index $k$ of \tcode{Extents} such that +for each rank index $k$ of \tcode{extents} such that the type of \tcode{slices...[$k$]} is not a collapsing slice type, \tcode{SubExt\-ents::static_extent(\placeholder{MAP_RANK}(slices, $k$))} equals the following, where $\Sigma_k$ @@ -25938,20 +26031,13 @@ \begin{itemize} \item \tcode{Extents::static_extent($k$)} - if $\Sigma_k$ denotes the \tcode{full_extent_t}; - otherwise - - \item - \tcode{0}, - if $\Sigma_k$ is a specialization of \tcode{strided_slice} and - \tcode{$\Sigma_k$::extent_type} denotes \tcode{constant_wrapper}; + if $\Sigma_k$ denotes \tcode{full_extent_t}; otherwise \item - \tcode{1 + (($\Sigma_k$::extent_type::value - 1) / $\Sigma_k$::stride_type::value)}, + \tcode{$\Sigma_k$::extent_type::value} if $\Sigma_k$ is a specialization of \tcode{strided_slice} whose - \tcode{extent_type} and \tcode{stride_type} - denote specializations of \tcode{constant_wrapper}; + \tcode{extent_type} denotes a specialization of \tcode{constant_wrapper}; \item otherwise, @@ -25969,7 +26055,7 @@ where $\sigma_k$ denotes \tcode{slices...[$k$]}: \begin{itemize} \item - \tcode{$\sigma_k$.extent == 0 ? 0 : 1 + ($\sigma_k$.extent - 1) / $\sigma_k$.stride} + \tcode{$\sigma_k$.extent} if the type of $\sigma_k$ is a specialization of \tcode{strided_slice}, \item otherwise, @@ -26134,7 +26220,7 @@ \item \tcode{stride(k) * s.stride} if the type of \tcode{s} is a specialization of \tcode{strided_slice} and -\tcode{s.stride < s.ex\-tent} is \tcode{true}, +\tcode{s.extent > 1} is \tcode{true}, where \tcode{s} is \tcode{slices...[$k$]}; \item otherwise, \tcode{stride($k$)}. diff --git a/source/support.tex b/source/support.tex index 203a1bf45f..3072e94615 100644 --- a/source/support.tex +++ b/source/support.tex @@ -852,7 +852,7 @@ #define @\defnlibxname{cpp_lib_string_subview}@ 202506L // also in \libheader{string}, \libheader{string_view} #define @\defnlibxname{cpp_lib_string_udls}@ 201304L // also in \libheader{string} #define @\defnlibxname{cpp_lib_string_view}@ 202403L // also in \libheader{string}, \libheader{string_view} -#define @\defnlibxname{cpp_lib_submdspan}@ 202511L // freestanding, also in \libheader{mdspan} +#define @\defnlibxname{cpp_lib_submdspan}@ 202603L // freestanding, also in \libheader{mdspan} #define @\defnlibxname{cpp_lib_syncbuf}@ 201803L // also in \libheader{iosfwd}, \libheader{syncstream} #define @\defnlibxname{cpp_lib_task}@ 202506L // also in \libheader{execution} #define @\defnlibxname{cpp_lib_text_encoding}@ 202306L // also in \libheader{text_encoding} From f5ba5a4b681e33e9b997f820378fe9ccb7755b72 Mon Sep 17 00:00:00 2001 From: Eisenwave Date: Thu, 2 Apr 2026 20:39:22 +0200 Subject: [PATCH 2/2] P3982R2 Split strided_slice into extent_slice and range_slice for C++26 (2/2) --- source/containers.tex | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/source/containers.tex b/source/containers.tex index 95518dac62..40962a6616 100644 --- a/source/containers.tex +++ b/source/containers.tex @@ -21280,7 +21280,7 @@ // \ref{mdspan.sub}, \tcode{submdspan} creation template - struct strided_slice; + struct extent_slice; template> struct range_slice; @@ -25545,7 +25545,7 @@ \item \tcode{is_convertible_v<$S$, IndexType>} is \tcode{true}; \item - $S$ is a specialization of \tcode{strided_slice} and + $S$ is a specialization of \tcode{extent_slice} and \tcode{is_convertible_v<$X$, IndexType>} is \tcode{true} for $X$ denoting \tcode{$S$::offset_type}, \tcode{$S$::extent_type}, and @@ -25588,7 +25588,7 @@ \item $S$ is a canonical \tcode{submdspan} index type for \tcode{IndexType}; or \item - $S$ is a specialization of \tcode{strided_slice} + $S$ is a specialization of \tcode{extent_slice} where all of the following hold: \begin{itemize} \item @@ -25604,7 +25604,7 @@ \pnum A type \tcode{S} is a \defnadj{collapsing}{slice type} if it is neither \tcode{full_extent_t} nor -a specialization of \tcode{strided_slice}. +a specialization of \tcode{extent_slice}. \begin{note} Each collapsing slice type in \tcode{submdspan_mapping}'s parameter pack of slice specifier types @@ -25615,7 +25615,7 @@ A type \tcode{S} is a \defnadj{unit-stride}{slice type} if \begin{itemize} \item - \tcode{S} is a specialization of \tcode{strided_slice} + \tcode{S} is a specialization of \tcode{extent_slice} where \tcode{S::stride_type} is a specialization of \tcode{constant_wrapper} and \tcode{S::stride_type::value} is equal to 1, or \item @@ -25634,7 +25634,7 @@ if \tcode{S} is \tcode{full_extent_t}; \item \range{E::index_type(s.offset)}{E::index_type(s.offset)}, - if \tcode{S} is a specialization of \tcode{strided_slice} and + if \tcode{S} is a specialization of \tcode{extent_slice} and \tcode{E::index_type(s.extent)} is zero; otherwise \item \range{E::index_type(s.offset)}{E::index_type(s.offset + s.extent)}, @@ -25652,7 +25652,7 @@ either $x$ is equal to \tcode{dynamic_extent}; or \begin{itemize} \item - if \tcode{S} is a specialization of \tcode{strided_slice}: + if \tcode{S} is a specialization of \tcode{extent_slice}: \begin{itemize} \item $o$ is less than or equal to $x$; @@ -25700,7 +25700,7 @@ contains the \tcode{submdspan} slice range of \tcode{s} for the $k^\text{th}$ extent of \tcode{e}; and \item - if \tcode{S} is a specialization of \tcode{strided_slice}, then: + if \tcode{S} is a specialization of \tcode{extent_slice}, then: \begin{itemize} \item \tcode{s.extent} is greater than or equal to zero, and \item either \tcode{s.extent} is less than two or \tcode{s.stride} is greater than zero. @@ -25710,17 +25710,17 @@ \rSec4[mdspan.sub.range.slices]{\tcode{Range slices}} \pnum -\tcode{strided_slice} and \tcode{range_slice} represent a set of +\tcode{extent_slice} and \tcode{range_slice} represent a set of \tcode{extent} regularly spaced integer indices. The indices start at \tcode{offset} and \tcode{first} respectively, and increase by increments of \tcode{stride}. -\indexlibraryglobal{strided_slice}% +\indexlibraryglobal{extent_slice}% \indexlibraryglobal{range_slice}% \begin{codeblock} namespace std { template - struct strided_slice { + struct extent_slice { using offset_type = OffsetType; using extent_type = ExtentType; using stride_type = StrideType; @@ -25740,7 +25740,7 @@ \end{codeblock} \pnum -\tcode{strided_slice} and \tcode{range_slice} +\tcode{extent_slice} and \tcode{range_slice} have the data members and special members specified above. They have no base classes or members other than those specified. @@ -25751,7 +25751,7 @@ are signed or unsigned integer types, or model \exposconcept{integral-constant-like}. \begin{note} -Both \tcode{strided_slice\{.offset = 1, .extent = 4, .stride = 3\}} and +Both \tcode{extent_slice\{.offset = 1, .extent = 4, .stride = 3\}} and \tcode{range_slice\{.first = 1, .last = 11, .stride = 3\}} indicate the indices \tcode{1}, \tcode{4}, \tcode{7}, and \tcode{10}. Indices are selected from the half-open interval \range{1}{1 + 10}. @@ -25793,14 +25793,14 @@ \begin{itemdecl} template - concept @\defexposconcept{is-strided-slice}@ = @\seebelow;@ + concept @\defexposconcept{is-extent-slice}@ = @\seebelow;@ \end{itemdecl} \begin{itemdescr} \pnum -The concept \tcode{\exposconcept{is-strided-slice}} +The concept \tcode{\exposconcept{is-extent-slice}} is satisfied and modeled if and only -if \tcode{T} is a specialization of \tcode{strided_slice}. +if \tcode{T} is a specialization of \tcode{extent_slice}. \end{itemdescr} \begin{itemdecl} @@ -25889,7 +25889,7 @@ \pnum \returns -\tcode{strided_slice\{ .offset = offset, .extent = extent, .stride = stride \};} +\tcode{extent_slice\{ .offset = offset, .extent = extent, .stride = stride \};} \end{itemdescr} \indexlibraryglobal{\exposid{canonical-slice}} @@ -25911,10 +25911,10 @@ return static_cast(std::move(s)); } else if constexpr (is_convertible_v) { return @\exposid{canonical-index}@(std::move(s)); -} else if constexpr (@\exposconcept{is-strided-slice}@) { +} else if constexpr (@\exposconcept{is-extent-slice}@) { auto c_extent = @\exposid{canonical-index}@(std::move(s.extent)); auto c_offset = @\exposid{canonical-index}@(std::move(s.offset)); - return strided_slice{ + return extent_slice{ .offset = @\exposid{canonical-index}@(std::move(s.extent)), .extent = @\exposid{canonical-index}@(std::move(s.offset)), .stride = @\exposid{canonical-index}@(std::move(s.stride)) @@ -26036,7 +26036,7 @@ \item \tcode{$\Sigma_k$::extent_type::value} - if $\Sigma_k$ is a specialization of \tcode{strided_slice} whose + if $\Sigma_k$ is a specialization of \tcode{extent_slice} whose \tcode{extent_type} denotes a specialization of \tcode{constant_wrapper}; \item @@ -26056,7 +26056,7 @@ \begin{itemize} \item \tcode{$\sigma_k$.extent} - if the type of $\sigma_k$ is a specialization of \tcode{strided_slice}, + if the type of $\sigma_k$ is a specialization of \tcode{extent_slice}, \item otherwise, $U - L$, where \range{$L$}{$U$} is the \tcode{submdspan} slice range @@ -26094,7 +26094,7 @@ \item \tcode{IT}, \item \tcode{full_extent_t}, \item a specialization of \tcode{constant_wrapper}, or - \item a specialization of \tcode{strided_slice}. + \item a specialization of \tcode{extent_slice}. \end{itemize} \end{itemize} @@ -26219,7 +26219,7 @@ \begin{itemize} \item \tcode{stride(k) * s.stride} -if the type of \tcode{s} is a specialization of \tcode{strided_slice} and +if the type of \tcode{s} is a specialization of \tcode{extent_slice} and \tcode{s.extent > 1} is \tcode{true}, where \tcode{s} is \tcode{slices...[$k$]}; \item