<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang xml:lang>
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2023-01-15" />
  <title>Padded mdspan layouts</title>
  <style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
  <style>
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ background-color: #f6f8fa; }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span { } 
code span.al { color: #ff0000; } 
code span.an { } 
code span.at { } 
code span.bn { color: #9f6807; } 
code span.bu { color: #9f6807; } 
code span.cf { color: #00607c; } 
code span.ch { color: #9f6807; } 
code span.cn { } 
code span.co { color: #008000; font-style: italic; } 
code span.cv { color: #008000; font-style: italic; } 
code span.do { color: #008000; } 
code span.dt { color: #00607c; } 
code span.dv { color: #9f6807; } 
code span.er { color: #ff0000; font-weight: bold; } 
code span.ex { } 
code span.fl { color: #9f6807; } 
code span.fu { } 
code span.im { } 
code span.in { color: #008000; } 
code span.kw { color: #00607c; } 
code span.op { color: #af1915; } 
code span.ot { } 
code span.pp { color: #6f4e37; } 
code span.re { } 
code span.sc { color: #9f6807; } 
code span.ss { color: #9f6807; } 
code span.st { color: #9f6807; } 
code span.va { } 
code span.vs { color: #9f6807; } 
code span.wa { color: #008000; font-weight: bold; } 
code.diff {color: #898887}
code.diff span.va {color: #6.0e28}
code.diff span.st {color: #bf0303}
</style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
a.self-link {
position: absolute;
top: 0;
left: calc(-1 * (3.5rem - 26px));
width: calc(3.5rem - 26px);
height: 2em;
text-align: center;
border: none;
transition: opacity .2s;
opacity: .5;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }

div#refs p { padding-left: 32px; text-indent: -32px; }
</style>
  <link href="data:text/html; charset=utf-8;charset=utf-8,%3Chtml%3E%0A%3Chead%3E%0A%3Ctitle%3EBIG%2DIP%20Per%20Request%20Policy%20Resource%20blocked%20page%3C%2Ftitle%3E%0A%3Cstyle%3E%0Abody%2C%20html%20%7B%0A%20%20%20%20padding%3A%200%3B%0A%20%20%20%20margin%3A%200%3B%0A%20%20%20%20height%3A%20100%25%3B%0A%7D%0Atable%2C%20td%2C%20th%2C%20div%20%7B%0A%20%20%20%20border%3A%200%3B%0A%20%20%20%20padding%3A%200%3B%0A%20%20%20%20margin%3A%200%3B%0A%7D%0Abody%2C%20table%2C%20td%2C%20th%2C%20div%2C%20input%2C%20h1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%20%7B%0A%20%20%20%20font%2Dfamily%20%3A%20Calibri%2C%20Tahoma%2C%20Verdana%2C%20Arial%2C%20Helvetica%2C%20Sans%2DSerif%3B%0A%20%20%20%20color%3A%20%23000000%3B%0A%20%20%20%20text%2Dalign%3A%20center%3B%0A%7D%0Abody%2C%20table%2C%20td%2C%20th%2C%20div%2C%20input%20%7B%0A%20%20%20%20font%2Dsize%20%3A%2014px%3B%0A%7D%0Ah1%2C%20h2%2C%20h3%2C%20h4%2C%20h5%2C%20h6%20%7B%0A%20%20%20%20font%2Dsize%20%3A%2018px%3B%0A%20%20%20%20text%2Ddecoration%3A%20none%3B%0A%20%20%20%20margin%2Dbottom%3A%200px%3B%0A%7D%0Abody%0A%7B%0A%20%20%20%20background%2Dcolor%3A%20%23FFFFFF%3B%0A%7D%0Atable%23page%5Fheader%0A%7B%0A%20%20%20%20width%3A%20100%25%3B%0A%20%20%20%20height%3A%2080px%3B%0A%20%20%20%20background%2Dcolor%3A%20%23FFFFFF%3B%0A%20%20%20%20background%2Drepeat%3A%20repeat%2Dx%3B%0A%7D%0Atable%23main%5Ftable%0A%7B%0A%20%20%20%20width%3A100%25%3B%0A%7D%0A%3C%2Fstyle%3E%0A%3C%2Fhead%3E%0A%0A%3Cscript%20language%3D%22javascript%22%3E%0Afunction%20OnLoad%28%29%20%7B%0A%20%20%20%20var%20category%20%3D%20%22Information%20Technology%22%3B%0A%20%20%20%20var%20categoryDiv%20%3D%20document%2EgetElementById%28%27display%5Fcategory%27%29%3B%0A%20%20%20%20if%20%28category%20%3D%3D%3D%20%22%22%29%20%7B%0A%20%20%20%20%20%20%20%20categoryDiv%2Estyle%2Evisibility%20%3D%20%27hidden%27%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20categoryDiv%2Estyle%2Evisibility%20%3D%20%27visible%27%3B%0A%20%20%20%20%20%20%20%20categoryDiv%2EinnerHTML%20%2B%3D%20%27%3Ctd%3E%27%20%2B%20%22The%20category%20reference%20is%3A%22%20%2B%20%27%20%27%20%2B%20category%20%2B%20%27%3C%2Ftd%3E%27%3B%0A%20%20%20%20%7D%0A%7D%0A%3C%2Fscript%3E%0A%3Cbody%20onload%3D%22OnLoad%28%29%3B%22%3E%0A%20%20%20%20%3Ctable%20id%3D%22page%5Fheader%22%3E%0A%20%20%20%20%20%20%20%20%3Ctr%3E%3Ctd%20style%3D%22padding%2Dleft%3A10px%3B%22%3E%0A%20%20%20%20%20%20%20%20%20%20%20%20%3Ch1%3ETransparent%20proxy%20access%20blocked%2E%20%3Cbr%3E%20Please%20verify%20your%20proxy%20setting%20are%20correct%2E%20%3Cbr%3E%20Contact%20CCHD%20if%20you%20need%20assistance%2E%3C%2Fh1%3E%20%20%20%20%20%20%20%20%3C%2Ftd%3E%3C%2Ftr%3E%0A%20%20%20%20%3C%2Ftable%3E%0A%20%20%20%20%3Ctable%20id%3D%27main%5Ftable%27%3E%0A%20%20%20%20%20%20%20%20%3Ctr%20id%3D%27display%5Fcategory%27%3E%3C%2Ftr%3E%0A%20%20%20%20%3C%2Ftable%3E%0A%3C%2Fbody%3E%0A%3C%2Fhtml%3E%0A" rel="icon" />
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
  
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Padded mdspan layouts</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P2642</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2023-01-15</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Mark Hoemmen (NVIDIA)<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</a>&gt;<br>
      Christian Trott (Sandia National Laboratories)<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.gov</a>&gt;<br>
      Damien Lebrun-Grandie (Oak Ridge National Laboratory)<br>&lt;<a href="mailto:lebrungrandt@ornl.gov" class="email">lebrungrandt@ornl.gov</a>&gt;<br>
      Malte Förster (NVIDIA)<br>&lt;<a href="mailto:mfoerster@nvidia.com" class="email">mfoerster@nvidia.com</a>&gt;<br>
      Jiaming Yuan (NVIDIA)<br>&lt;<a href="mailto:jiamingy@nvidia.com" class="email">jiamingy@nvidia.com</a>&gt;<br>
    </td>
  </tr>
</table>

</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#authors" id="toc-authors"><span class="toc-section-number">1</span> Authors</a></li>
<li><a href="#revision-history" id="toc-revision-history"><span class="toc-section-number">2</span> Revision history</a>
<ul>
<li><a href="#revision-0" id="toc-revision-0"><span class="toc-section-number">2.1</span> Revision 0</a></li>
<li><a href="#revision-1" id="toc-revision-1"><span class="toc-section-number">2.2</span> Revision 1</a></li>
<li><a href="#revision-2" id="toc-revision-2"><span class="toc-section-number">2.3</span> Revision 2</a></li>
</ul></li>
<li><a href="#proposed-changes-and-justification" id="toc-proposed-changes-and-justification"><span class="toc-section-number">3</span> Proposed changes and
justification</a>
<ul>
<li><a href="#summary-of-proposed-changes" id="toc-summary-of-proposed-changes"><span class="toc-section-number">3.1</span> Summary of proposed
changes</a></li>
<li><a href="#two-new-mdspan-layouts" id="toc-two-new-mdspan-layouts"><span class="toc-section-number">3.2</span> Two new mdspan layouts</a>
<ul>
<li><a href="#optimizations-over-layout_stride" id="toc-optimizations-over-layout_stride"><span class="toc-section-number">3.2.1</span> Optimizations over
<code>layout_stride</code></a></li>
<li><a href="#new-layouts-unify-two-use-cases" id="toc-new-layouts-unify-two-use-cases"><span class="toc-section-number">3.2.2</span> New layouts unify two use
cases</a></li>
<li><a href="#design-change-from-r0-to-r1" id="toc-design-change-from-r0-to-r1"><span class="toc-section-number">3.2.3</span> Design change from R0 to
R1</a></li>
<li><a href="#padding-stride-equality-for-layout-mapping-conversions" id="toc-padding-stride-equality-for-layout-mapping-conversions"><span class="toc-section-number">3.2.4</span> Padding stride equality for
layout mapping conversions</a></li>
<li><a href="#new-layout-mapping-constructors-in-r2" id="toc-new-layout-mapping-constructors-in-r2"><span class="toc-section-number">3.2.5</span> New layout mapping constructors
in R2</a></li>
<li><a href="#conversion-from-layout_left-to-layout_left_padded" id="toc-conversion-from-layout_left-to-layout_left_padded"><span class="toc-section-number">3.2.6</span> Conversion from
<code>layout_left</code> to <code>layout_left_padded</code></a></li>
<li><a href="#conversion-from-layout_stride-to-layout_left_padded" id="toc-conversion-from-layout_stride-to-layout_left_padded"><span class="toc-section-number">3.2.7</span> Conversion from
<code>layout_stride</code> to <code>layout_left_padded</code></a></li>
</ul></li>
<li><a href="#integration-with-submdspan" id="toc-integration-with-submdspan"><span class="toc-section-number">3.3</span> Integration with
<code>submdspan</code></a>
<ul>
<li><a href="#layout_left_padded-and-layout_left-cases" id="toc-layout_left_padded-and-layout_left-cases"><span class="toc-section-number">3.3.1</span> <code>layout_left_padded</code>
and <code>layout_left</code> cases</a></li>
<li><a href="#layout_right_padded-and-layout_right-cases" id="toc-layout_right_padded-and-layout_right-cases"><span class="toc-section-number">3.3.2</span> <code>layout_right_padded</code>
and <code>layout_right</code> cases</a></li>
</ul></li>
<li><a href="#examples" id="toc-examples"><span class="toc-section-number">3.4</span> Examples</a>
<ul>
<li><a href="#directly-call-c-blas-without-checks" id="toc-directly-call-c-blas-without-checks"><span class="toc-section-number">3.4.1</span> Directly call C BLAS without
checks</a></li>
<li><a href="#overaligned-access" id="toc-overaligned-access"><span class="toc-section-number">3.4.2</span> Overaligned access</a></li>
</ul></li>
<li><a href="#alternatives" id="toc-alternatives"><span class="toc-section-number">3.5</span> Alternatives</a></li>
<li><a href="#implementation-experience" id="toc-implementation-experience"><span class="toc-section-number">3.6</span> Implementation experience</a></li>
<li><a href="#desired-ship-vehicle" id="toc-desired-ship-vehicle"><span class="toc-section-number">3.7</span> Desired ship vehicle</a></li>
</ul></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">4</span> Wording</a>
<ul>
<li><a href="#class-template-layout_left_paddedmapping-mdspan.layout.left_padded" id="toc-class-template-layout_left_paddedmapping-mdspan.layout.left_padded"><span class="toc-section-number">4.1</span> Class template
<code>layout_left_padded::mapping</code>
[mdspan.layout.left_padded]</a></li>
<li><a href="#class-template-layout_right_paddedmapping-mdspan.layout.right_padded" id="toc-class-template-layout_right_paddedmapping-mdspan.layout.right_padded"><span class="toc-section-number">4.2</span> Class template
<code>layout_right_padded::mapping</code>
[mdspan.layout.right_padded]</a></li>
<li><a href="#layout-specializations-of-submdspan_mapping-mdspan.submdspan.mapping" id="toc-layout-specializations-of-submdspan_mapping-mdspan.submdspan.mapping"><span class="toc-section-number">4.3</span> Layout specializations of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping]</a></li>
<li><a href="#layout-specializations-of-submdspan_offset-mdspan.submdspan.offset" id="toc-layout-specializations-of-submdspan_offset-mdspan.submdspan.offset"><span class="toc-section-number">4.4</span> Layout specializations of
<code>submdspan_offset</code> [mdspan.submdspan.offset]</a></li>
</ul></li>
</ul>
</div>
<h1 data-number="1" id="authors"><span class="header-section-number">1</span> Authors<a href="#authors" class="self-link"></a></h1>
<ul>
<li><p>Mark Hoemmen (mhoemmen@nvidia.com) (NVIDIA)</p></li>
<li><p>Christian Trott (crtrott@sandia.gov) (Sandia National
Laboratories)</p></li>
<li><p>Damien Lebrun-Grandie (lebrungrandt@ornl.gov) (Oak Ridge National
Laboratory)</p></li>
<li><p>Malte Förster (mfoerster@nvidia.com) (NVIDIA)</p></li>
<li><p>Jiaming Yuan (jiamingy@nvidia.com) (NVIDIA)</p></li>
</ul>
<h1 data-number="2" id="revision-history"><span class="header-section-number">2</span> Revision history<a href="#revision-history" class="self-link"></a></h1>
<h2 data-number="2.1" id="revision-0"><span class="header-section-number">2.1</span> Revision 0<a href="#revision-0" class="self-link"></a></h2>
<p>Revision 0 submitted 2022-09-14.</p>
<h2 data-number="2.2" id="revision-1"><span class="header-section-number">2.2</span> Revision 1<a href="#revision-1" class="self-link"></a></h2>
<p>Revision 1 submitted 2022-10-15.</p>
<ul>
<li><p>Change padding stride to function as an overalignment factor if
less than the extent to pad. Remove mapping constructor that takes
<code>extents_type</code> and
<code>extents&lt;index_type, padding_stride&gt;</code>, because the
latter may not be the actual padding stride.</p></li>
<li><p>Make converting constructors from
<code>layout_{left,right}_padded::mapping</code> to
<code>layout_{left,right}::mapping</code> use Mandates rather than
Constraints to check compile-time stride compatibility.</p></li>
<li><p>Mandate that <code>layout_{left,right}_padded::mapping</code>’s
actual padding stride, if known at compile time, be representable as a
value of type <code>index_type</code> (as well as of type
<code>size_t</code>, the previous requirement).</p></li>
<li><p>Add section explaining why we don’t permit conversion from more
aligned to less aligned.</p></li>
<li><p>Fixed typos in Wording</p></li>
<li><p>Fix formatting in non-Wording, and add links for BLAS and
LAPACK</p></li>
</ul>
<h2 data-number="2.3" id="revision-2"><span class="header-section-number">2.3</span> Revision 2<a href="#revision-2" class="self-link"></a></h2>
<p>Revision 2 to be submitted 2023-01-15.</p>
<ul>
<li><p>Rebase atop P2630R2 (not R0).</p></li>
<li><p>Fix synopsis declaration of
<code>layout_{left,right}_padded</code> to declare the
<code>mapping</code> as well</p></li>
<li><p>Add that each specialization of
<code>layout_{left,right}_padded</code> meets the layout mapping policy
requirements and is a trivial type</p></li>
<li><p>Simplify <code>layout_{left,right}_padded::mapping</code>
constructor conditions</p></li>
<li><p>Add default constructors for
<code>layout_{left,right}_padded::mapping</code>; <code>=default</code>
for
<em><code>actual-padding-stride</code></em><code>!= dynamic_extent</code>,
not <code>=default</code> otherwise</p></li>
<li><p>Add converting constructors from
<code>layout_(left,right)::mapping</code> to
<code>layout_(left,right)_padded::mapping</code></p></li>
<li><p>Add converting constructors from
<code>layout_stride::mapping</code> to
<code>layout_(left,right)_padded::mapping</code></p></li>
<li><p>Add <code>operator==</code> to
<code>layout_{left,right}_padded::mapping</code></p></li>
<li><p>In Remarks for the existing constructor
<code>layout_stride::mapping(const StridedLayoutMapping&amp;)</code>,
add <code>layout_left_padded</code> and <code>layout_right_padded</code>
to the list of the layouts in the expression inside
<code>explicit</code></p></li>
<li><p>Reformat from Bikeshed to Pandoc</p></li>
</ul>
<h1 data-number="3" id="proposed-changes-and-justification"><span class="header-section-number">3</span> Proposed changes and
justification<a href="#proposed-changes-and-justification" class="self-link"></a></h1>
<h2 data-number="3.1" id="summary-of-proposed-changes"><span class="header-section-number">3.1</span> Summary of proposed changes<a href="#summary-of-proposed-changes" class="self-link"></a></h2>
<p>We propose two new mdspan layouts, <code>layout_left_padded</code>
and <code>layout_right_padded</code>. These layouts support two use
cases:</p>
<ol type="1">
<li><p>array layouts that are contiguous in one dimension, as supported
by commonly used libraries like the
<a href="https://netlib.org/blas/blast-forum/">BLAS</a> (Basic Linear
Algebra Subroutines; see P1417 and P1674 for historical overview and
references) and <a href="https://netlib.org/lapack/">LAPACK</a> (Linear
Algebra PACKage); and</p></li>
<li><p>“padded” storage for overaligned access of the start of every
contiguous segment of the array.</p></li>
</ol>
<p>We also propose changing <code>submdspan</code> of a
<code>layout_left</code> resp. <code>layout_right</code> mdspan to
return <code>layout_left_padded</code> resp.
<code>layout_right_padded</code> instead of <code>layout_stride</code>,
when the slice arguments permit it.</p>
<h2 data-number="3.2" id="two-new-mdspan-layouts"><span class="header-section-number">3.2</span> Two new mdspan layouts<a href="#two-new-mdspan-layouts" class="self-link"></a></h2>
<p>The two new mdspan layouts <code>layout_left_padded</code> and
<code>layout_right_padded</code> are strided, unique layouts. If the
rank is zero or one, then the layouts behave exactly like
<code>layout_left</code> resp. <code>layout_right</code>. If the rank is
two or more, then the layouts implement a special case of
<code>layout_stride</code> where only one stride may differ from the
extent that in <code>layout_left</code> resp. <code>layout_right</code>
would completely define the stride. We call that stride the <em>padding
stride</em>, and the extent that in <code>layout_left</code> resp.
<code>layout_right</code> would define it the <em>extent to pad</em>.
The padding stride of <code>layout_left_padded</code> is
<code>stride(1)</code>, and the extent to pad is <code>extent(0)</code>.
The padding stride of <code>layout_right_padded</code> is
<code>stride(rank() - 2)</code>, and the extent to pad is
<code>extent(rank() - 1)</code>. All other strides of
<code>layout_left_padded</code> are the same as in
<code>layout_left</code>, and all other strides of
<code>layout_right_padded</code> are the same as in
<code>layout_right</code>.</p>
<h3 data-number="3.2.1" id="optimizations-over-layout_stride"><span class="header-section-number">3.2.1</span> Optimizations over
<code>layout_stride</code><a href="#optimizations-over-layout_stride" class="self-link"></a></h3>
<p>The two new layouts offer the following optimizations over
<code>layout_stride</code>.</p>
<ol type="1">
<li><p>They guarantee at compile time that one extent always has
stride-1 access. While <code>layout_stride</code>’s member functions are
all <code>constexpr</code>, its mapping constructor takes the strides as
a <code>std::array</code> with <code>rank()</code> size.</p></li>
<li><p>They do not need to store any strides if the padding stride is
known at compile time. Even if the padding stride is a run-time value,
these layouts only need to store the one stride value (as
<code>index_type</code>). The <code>layout_stride::mapping</code> class
must store all <code>rank()</code> stride values.</p></li>
</ol>
<h3 data-number="3.2.2" id="new-layouts-unify-two-use-cases"><span class="header-section-number">3.2.2</span> New layouts unify two use
cases<a href="#new-layouts-unify-two-use-cases" class="self-link"></a></h3>
<p>The proposed layouts unify two different use cases:</p>
<ol type="1">
<li><p>overaligned access to the beginning of each contiguous segment of
elements, and</p></li>
<li><p>representing exactly the data layout assumed by the General (GE)
matrix type in the BLAS’ C binding.</p></li>
</ol>
<p>Regarding (1), an appropriate choice of padding can ensure any
desired overalignment of the beginning of each contiguous segment of
elements in an mdspan, as long as the entire memory allocation has the
same overalignment. This is useful for hardware features that require or
perform better with overaligned access, such as SIMD (Single Instruction
Multiple Data) instructions.</p>
<p>Regarding (2), the padding stride is the same as BLAS’ “leading
dimension” of the matrix (<code>LDA</code>) argument. Unlike
<code>layout_left</code> and <code>layout_right</code>, any subview of a
contiguous subset of rows and columns of a rank-2
<code>layout_left_padded</code> or <code>layout_right_padded</code>
mdspan preserves the layout. For example, if <code>A</code> is a rank-2
mdspan whose layout is
<code>layout_left_padded&lt;padding_stride&gt;</code>, then
<code>submdspan(A, tuple{r1, r2}, tuple{c1, c2})</code> also has layout
<code>layout_left_padded&lt;padding_stride&gt;</code> with the same
padding stride as before. The BLAS and algorithms that use it (such as
the blocked algorithms in LAPACK) depend on this ability to operate on
contiguous submatrices with the same layout as their parent. For this
reason, we can replace the <code>layout_blas_general</code> layout in
<a href="https://wg21.link/p1673">P1673</a> with
<code>layout_left_padded</code> and <code>layout_right_padded</code>.
Making most effective use of the new layouts in code that uses P1673
calls for integrating them with <code>submdspan</code>. This is why we
propose the following changes as well.</p>
<h3 data-number="3.2.3" id="design-change-from-r0-to-r1"><span class="header-section-number">3.2.3</span> Design change from R0 to R1<a href="#design-change-from-r0-to-r1" class="self-link"></a></h3>
<p>A design change from R0 to R1 of this paper makes this overalignment
case easier to use and more like the existing
<code>std::assume_aligned</code> interface. In R0 of this paper, the
user’s padding input parameter (either a compile-time
<code>padding_stride</code> or a run-time value) was exactly the padding
stride. As such, it had to be greater than or equal to the extent to
pad. For example, if users had an <code>extent(0)</code> of 13 and
wanted to overalign the corresponding <code>stride(1)</code> to a
multiple of 4, they would have had to specify
<code>layout_left_padded&lt;16&gt;</code>. This was inconsistent with
<code>std::assume_aligned</code>, whose template argument (the byte
alignment) would need to be <code>4 * sizeof(element_type)</code>. Also,
users who wanted a compile-time padding stride would have needed to
compute it themselves from the corresponding compile-time extent, rather
than prespecifying a fixed overalignment factor that could be used for
any extent. This was not only harder to use, but it made the layout
itself (not just the layout mapping) depend on the extent. That was
inconsistent with the existing mdspan layouts, where the layout type
itself (e.g., <code>layout_left</code>) is always a function from
<code>extents</code> specialization to layout mapping.</p>
<p>In R1 and subsequent revisions of this paper, we interpret the case
where the input padding stride is less than the extent to pad as an
“overalignment factor” instead of a stride. To revisit the above
example, <code>layout_left_padded&lt;4&gt;</code> would take an
<code>extent(0)</code> of 13 and round up the corresponding
<code>stride(1)</code> to 16. However, as before,
<code>layout_left_padded&lt;17&gt;</code> would take an
<code>extent(0)</code> of 13 and round up the corresponding
<code>stride(1)</code> to 17. The rule is consistent: the actual padding
stride is always the next multiple of the input padding stride greater
than or equal to the extent-to-pad.</p>
<p>In R0 of this paper, the following alias</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> overaligned_matrix_t <span class="op">=</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dextents<span class="op">&lt;</span><span class="dt">size_t</span>, <span class="dv">2</span><span class="op">&gt;</span>, layout_right_padded<span class="op">&lt;</span><span class="dv">4</span><span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>would only be meaningful if the run-time extents are less than or
equal to 4. In R1 and subsequent revisions, this alias would always mean
“the padding stride rounds up the rightmost extent to a multiple of 4,
whatever the extent may be.” R0 had no way to express that use case with
a compile-time input padding stride. This is important for hardware
features and compiler optimizations that require overalignment of
multidimensional arrays.</p>
<h3 data-number="3.2.4" id="padding-stride-equality-for-layout-mapping-conversions"><span class="header-section-number">3.2.4</span> Padding stride equality for
layout mapping conversions<a href="#padding-stride-equality-for-layout-mapping-conversions" class="self-link"></a></h3>
<p><code>layout_left_padded&lt;padding_stride&gt;::mapping&lt;Extents&gt;</code>
has a converting constructor from
<code>layout_left_padded&lt;other_padding_stride&gt;::mapping&lt;OtherExtents&gt;</code>.
Similarly,
<code>layout_right_padded&lt;padding_stride&gt;::mapping&lt;Extents&gt;</code>
has a converting constructor from
<code>layout_right_padded&lt;other_padding_stride&gt;::mapping&lt;OtherExtents&gt;</code>.
These constructors require, among other conditions, that if
<code>padding_stride</code> and <code>other_padding_stride</code> do not
equal <code>dynamic_extent</code>, then <code>padding_stride</code>
equals <code>other_padding_stride</code>.</p>
<p>Users may ask why they can’t convert a more overaligned mapping, such
as <code>layout_left_padded&lt;4&gt;::mapping</code>, to a less
overaligned mapping, such as
<code>layout_left_padded&lt;2&gt;::mapping</code>. The problem is that
this may not be correct for all extents. For example, the following code
would be incorrect if it were well formed (it is not, in this
proposal).</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span><span class="dv">4</span><span class="op">&gt;::</span>mapping m_orig<span class="op">{</span>extents<span class="op">{</span><span class="dv">9</span>, <span class="dv">2</span><span class="op">}}</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;::</span>mapping m_new<span class="op">(</span>m_orig<span class="op">)</span>;</span></code></pre></div>
<p>The issue is that <code>m_orig</code> has an underlying (“physical”)
layout of <code>extents{12, 2}</code>, but
<code>layout_left_padded&lt;2&gt;::mapping{extents{9, 2}}</code> would
have an underlying layout of <code>extents{10, 2}</code>. That is,
<code>layout_left_padded&lt;4&gt;::mapping{extents{9, 2}}.stride(1)</code>
is 12, but
<code>layout_left_padded&lt;2&gt;::mapping{extents{9, 2}}.stride(1)</code>
is 10.</p>
<p>In case one is tempted to permit assigning dynamic padding stride to
static padding stride, the following code would also be incorrect if it
were well formed (it is not, in this proposal). Again,
<code>m_orig.stride(1)</code> is 12.</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span>dynamic_extent<span class="op">&gt;::</span>mapping m_orig<span class="op">{</span>extents<span class="op">{</span><span class="dv">9</span>, <span class="dv">2</span><span class="op">}</span>, <span class="dv">4</span><span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;::</span>mapping m_new<span class="op">(</span>m_orig<span class="op">)</span>;</span></code></pre></div>
<p>The following code is well formed in this proposal, and it gives
<code>m_new</code> the expected original padding stride of 12.</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span>dynamic_extent<span class="op">&gt;::</span>mapping m_orig<span class="op">{</span>extents<span class="op">{</span><span class="dv">9</span>, <span class="dv">2</span><span class="op">}</span>, <span class="dv">4</span><span class="op">}</span>;</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span>dynamic_extent<span class="op">&gt;::</span>mapping m_new<span class="op">(</span>m_orig<span class="op">)</span>;</span></code></pre></div>
<p>Similarly, the following code is well formed in this proposal, and it
gives <code>m_new</code> the expected original padding stride of 12.</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span><span class="dv">4</span><span class="op">&gt;::</span>mapping m_orig<span class="op">{</span>extents<span class="op">{</span><span class="dv">9</span>, <span class="dv">2</span><span class="op">}}</span>;</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>layout_left_padded<span class="op">&lt;</span>dynamic_extent<span class="op">&gt;::</span>mapping m_new<span class="op">(</span>m_orig<span class="op">)</span>;</span></code></pre></div>
<h3 data-number="3.2.5" id="new-layout-mapping-constructors-in-r2"><span class="header-section-number">3.2.5</span> New layout mapping
constructors in R2<a href="#new-layout-mapping-constructors-in-r2" class="self-link"></a></h3>
<p>R2 of this proposal adds new constructors to
<code>layout_{left,right}_padded::mapping</code>. First, it adds default
constructors that default-construct the <code>extents_type</code>
object, but otherwise behave like the
<code>mapping(const extents_type&amp;)</code> constructor. That is, they
fill in the correct run-time padding stride value, if this is possible
given the <code>padding_stride</code> template argument. Second, R2 adds
more converting constructors. For
<code>layout_left_padded::mapping</code>, R2 adds a converting
constructor from each of the following.</p>
<ul>
<li><p><code>layout_left::mapping&lt;OtherExtents&gt;</code></p></li>
<li><p><code>layout_stride::mapping&lt;OtherExtents&gt;</code></p></li>
</ul>
<p>For <code>layout_right_padded::mapping</code>, R2 adds a converting
constructor from each of the following.</p>
<ul>
<li><p><code>layout_right::mapping&lt;OtherExtents&gt;</code></p></li>
<li><p><code>layout_stride::mapping&lt;OtherExtents&gt;</code></p></li>
</ul>
<h3 data-number="3.2.6" id="conversion-from-layout_left-to-layout_left_padded"><span class="header-section-number">3.2.6</span> Conversion from
<code>layout_left</code> to <code>layout_left_padded</code><a href="#conversion-from-layout_left-to-layout_left_padded" class="self-link"></a></h3>
<p>The converting constructor from <code>layout_left::mapping</code> to
<code>layout_left_padded::mapping</code> exists by analogy with the
existing constructor
<code>layout_stride::mapping(const StridedLayoutMapping&amp; other)</code>
(<em>[mdspan.layout.stride.cons]</em>) that can convert from
<code>layout_left::mapping</code> to
<code>layout_stride::mapping</code>. <code>layout_left</code> expresses
a special case of <code>layout_left_padded</code>, just as
<code>layout_left</code> expresses a special case of
<code>layout_stride</code>. Thus, this is an implicit conversion as long
as the conversion from the input’s <code>extents_type</code> to the
result’s <code>extents_type</code> would be implicit.</p>
<p>This conversion is useful for C++ wrappers for the BLAS or LAPACK.
<code>layout_left_padded&lt;dynamic_extent&gt;::mapping&lt;dextent&lt;int, 2&gt;&gt;</code>
expresses in C++ exactly the 2-D array layout that the BLAS and LAPACK
accept, including their requirement that the extents and
<code>stride(1)</code> all be run-time values. Thus, a C++ wrapper for
the BLAS (see P1673) or LAPACK might reasonably have a specialization
for <code>mdspan</code> with layout
<code>layout_left_padded&lt;dynamic_extent&gt;::mapping&lt;dextent&lt;int, 2&gt;&gt;</code>,
that can call with very few error checks or layout conversions directly
into an existing C or Fortran BLAS or LAPACK library. However, users
would reasonably want to create their 2-D arrays as
<code>layout_left</code>, since it’s a simpler layout that doesn’t need
to store the column stride. The converting constructor from
<code>layout_left::mapping</code> to
<code>layout_left_padded::mapping</code> would let users or libraries
easily convert from the less general <code>layout_left</code> to the
slightly more general <code>layout_left_padded</code> that a C++ BLAS or
LAPACK wrapper would naturally use.</p>
<h3 data-number="3.2.7" id="conversion-from-layout_stride-to-layout_left_padded"><span class="header-section-number">3.2.7</span> Conversion from
<code>layout_stride</code> to <code>layout_left_padded</code><a href="#conversion-from-layout_stride-to-layout_left_padded" class="self-link"></a></h3>
<p>The converting constructor from <code>layout_stride::mapping</code>
to <code>layout_left_padded::mapping</code> exists by analogy with the
existing converting constructor from <code>layout_stride::mapping</code>
to <code>layout_left::mapping</code>. This constructor is
<code>explicit</code> for <code>rank() &gt; 0</code>, because it always
converts from a more general case to a more specific case.</p>
<p>Explicit conversions to <code>layout_stride::mapping</code> are
useful because <code>layout_stride::mapping</code> can express all the
layout mappings in the Standard and this proposal. It’s like a
“type-erased” version of all of them. For example, a library of
<code>mdspan</code> algorithms might reasonably convert to
<code>layout_stride::mapping</code> for some less performance-critical
algorithms, as a way to minimize algorithm instantiations for different
layouts.</p>
<h2 data-number="3.3" id="integration-with-submdspan"><span class="header-section-number">3.3</span> Integration with
<code>submdspan</code><a href="#integration-with-submdspan" class="self-link"></a></h2>
<p>We propose changing <code>submdspan</code>
(<a href="https://wg21.link/p2630">see P2630</a>) of a
<code>layout_left</code> resp. <code>layout_right</code> mdspan to
return <code>layout_left_padded</code> resp.
<code>layout_right_padded</code> instead of <code>layout_stride</code>,
if the slice arguments permit it. Taking the <code>submdspan</code> of a
<code>layout_left_padded</code> resp. <code>layout_right_padded</code>
mdspan will preserve the layout, again if the slice arguments permit
it.</p>
<p>The phrase “if the slice arguments permit it” means the
following.</p>
<h3 data-number="3.3.1" id="layout_left_padded-and-layout_left-cases"><span class="header-section-number">3.3.1</span>
<code>layout_left_padded</code> and <code>layout_left</code> cases<a href="#layout_left_padded-and-layout_left-cases" class="self-link"></a></h3>
<p>In what follows, let <code>left_submatrix</code> be the following
function,</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Elt, <span class="kw">class</span> Extents, <span class="kw">class</span> Layout,</span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> Accessor, <span class="kw">class</span> S0, <span class="kw">class</span> S1<span class="op">&gt;</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">requires</span><span class="op">(</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>S0,</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a>    tuple<span class="op">&lt;</span><span class="kw">typename</span> Extents<span class="op">::</span>index_type,</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> Extents<span class="op">::</span>index_type<span class="op">&gt;&gt;</span> <span class="kw">and</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>S1,</span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>    tuple<span class="op">&lt;</span><span class="kw">typename</span> Extents<span class="op">::</span>index_type,</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> Extents<span class="op">::</span>index_type<span class="op">&gt;&gt;</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> left_submatrix<span class="op">(</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>Elt, Extents, Layout, Accessor<span class="op">&gt;</span> X, S0 s0, S1 s1<span class="op">)</span></span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">[]&lt;</span><span class="dt">size_t</span> <span class="op">...</span> Indices<span class="op">&gt;(</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> tuple<span class="op">{</span> <span class="op">(</span>Indices, full_extent<span class="op">)...</span> <span class="op">}</span>;</span>
<span id="cb6-17"><a href="#cb6-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}(</span>make_index_sequence<span class="op">&lt;</span>X<span class="op">.</span>rank<span class="op">()</span> <span class="op">-</span> <span class="dv">2</span><span class="op">&gt;())</span>;</span>
<span id="cb6-18"><a href="#cb6-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> apply<span class="op">([&amp;](</span>full_extent_t <span class="op">...</span> fe<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-19"><a href="#cb6-19" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> submdspan<span class="op">(</span>X, s0, s1, fe<span class="op">...)</span>;</span>
<span id="cb6-20"><a href="#cb6-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, full_extents<span class="op">)</span>;</span>
<span id="cb6-21"><a href="#cb6-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>let <code>index_type</code> be an integral type, let <code>s0</code>
be an object of a type <code>S0</code> such that
<code>is_convertible_v&lt;S0, tuple&lt;index_type, index_type&gt;&gt;</code>
is <code>true</code>, and let <code>s1</code> be an object of a type
<code>S1</code> such that
<code>is_convertible_v&lt;S1, tuple&lt;index_type, index_type&gt;&gt;</code>
is <code>true</code>.</p>
<p>Let <code>X</code> be an <code>mdspan</code> with rank at least two
with <code>decltype(X)::index_type</code> naming the same type as
<code>index_type</code>, whose layout is
<code>layout_left_padded&lt;padding_stride_X&gt;</code> for some
<code>constexpr size_t padding_stride_X</code>. Let <code>X_sub</code>
be the object returned from <code>left_submatrix(X, s0, s1)</code>.
Then, <code>X_sub</code> is an <code>mdspan</code> of rank
<code>X.rank()</code> with layout
<code>layout_left_padded&lt;padding_stride_X&gt;</code>, and
<code>X_sub.stride(1)</code> equals <code>X.stride(1)</code>.</p>
<p>Let <code>Z</code> be an <code>mdspan</code> with rank at least two
with <code>decltype(Z)::index_type</code> naming the same type as
<code>index_type</code>, whose layout is <code>layout_left</code>. Let
<code>Z_sub</code> be the object returned from
<code>left_submatrix(Z, s0, s1)</code>. Then, <code>Z_sub</code> is an
<code>mdspan</code> of rank <code>Z.rank()</code> with layout
<code>layout_left_padded&lt;padding_stride_Z&gt;</code>, where
<code>padding_stride_Z</code> is</p>
<ul>
<li><p><code>srm1_val1 - srm1_val0</code>, if <code>srm1</code> is
convertible to
<code>tuple&lt;integral_constant&lt;decltype(W)::index_type, srm1_val0&gt;, integral_constant&lt;decltype(W)::index_type, srm1_val1&gt;&gt;</code>
with <code>srm1_val1</code> greater than to equal to
<code>srm1_val0</code>; else,</p></li>
<li><p><code>dynamic_rank</code>.</p></li>
</ul>
<p>Also, <code>Z_sub.stride(1)</code> equals
<code>Z.stride(1)</code>.</p>
<h3 data-number="3.3.2" id="layout_right_padded-and-layout_right-cases"><span class="header-section-number">3.3.2</span>
<code>layout_right_padded</code> and <code>layout_right</code> cases<a href="#layout_right_padded-and-layout_right-cases" class="self-link"></a></h3>
<p>In what follows, let <code>right_submatrix</code> be the following
function,</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Elt, <span class="kw">class</span> Extents, <span class="kw">class</span> Layout,</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> Accessor, <span class="kw">class</span> Srm2, <span class="kw">class</span> Srm1<span class="op">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">requires</span><span class="op">(</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>Srm2,</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>    tuple<span class="op">&lt;</span><span class="kw">typename</span> Extents<span class="op">::</span>index_type,</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> Extents<span class="op">::</span>index_type<span class="op">&gt;&gt;</span> <span class="kw">and</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>Srm1,</span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>    tuple<span class="op">&lt;</span><span class="kw">typename</span> Extents<span class="op">::</span>index_type,</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> Extents<span class="op">::</span>index_type<span class="op">&gt;&gt;</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> right_submatrix<span class="op">(</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span>Elt, Extents, Layout, Accessor<span class="op">&gt;</span> X, Srm2 srm2, Srm1 srm1<span class="op">)</span></span>
<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">[]&lt;</span><span class="dt">size_t</span> <span class="op">...</span> Indices<span class="op">&gt;(</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> tuple<span class="op">{</span> <span class="op">(</span>Indices, full_extent<span class="op">)...</span> <span class="op">}</span>;</span>
<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a>    <span class="op">}(</span>make_index_sequence<span class="op">&lt;</span>X<span class="op">.</span>rank<span class="op">()</span> <span class="op">-</span> <span class="dv">2</span><span class="op">&gt;())</span>;</span>
<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> apply<span class="op">([&amp;](</span>full_extent_t <span class="op">...</span> fe<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>      <span class="cf">return</span> submdspan<span class="op">(</span>X, fe<span class="op">...</span>, srm2, srm1<span class="op">)</span>;</span>
<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, full_extents<span class="op">)</span>;</span>
<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>let <code>srm2</code> (“s of rank minus 2”) be an object of a type
<code>Srm2</code> such that
<code>is_convertible_v&lt;S0, tuple&lt;index_type_X, index_type_X&gt;&gt;</code>
is <code>true</code>, and let <code>srm1</code> (“s of rank minus 1”) be
an object of a type <code>Srm1</code> such that
<code>is_convertible_v&lt;S1, tuple&lt;index_type_X, index_type_X&gt;&gt;</code>
is <code>true</code>.</p>
<p>Similarly, let <code>Y</code> be an <code>mdspan</code> with rank at
least two whose layout is
<code>layout_right_padded&lt;padding_stride_Y&gt;</code> for some
<code>constexpr size_t padding_stride_Y</code>. Let
<code>index_type_Y</code> name the type
<code>decltype(Y)::index_type</code>. Let <code>srm2</code> (“S of rank
minus 2”) be an object of a type <code>Srm2</code> such that
<code>is_convertible_v&lt;Srm2, tuple&lt;index_type_Y, index_type_Y&gt;&gt;</code>
is <code>true</code>, and let <code>srm1</code> (“S of rank minus 1”) be
an object of a type <code>Srm1</code> such that
<code>is_convertible_v&lt;Srm1, tuple&lt;index_type_Y, index_type_Y&gt;&gt;</code>
is <code>true</code>. In the following code fragment,</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">[]&lt;</span><span class="dt">size_t</span> <span class="op">...</span> Indices<span class="op">&gt;(</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> tuple<span class="op">{(</span>Indices, full_extent<span class="op">)...}</span>;</span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}(</span>make_index_sequence<span class="op">&lt;</span>Y<span class="op">.</span>rank<span class="op">()</span> <span class="op">-</span> <span class="dv">2</span><span class="op">&gt;())</span>;</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> Y_sub <span class="op">=</span> apply<span class="op">([&amp;](</span>full_extent_t<span class="op">...</span> fe<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> submdspan<span class="op">(</span>Y, fe<span class="op">...</span>, srm2, srm1<span class="op">)</span>;</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>, full_extents<span class="op">)</span>;</span></code></pre></div>
<p><code>Y_sub</code> is an <code>mdspan</code> of rank
<code>Y.rank()</code> with layout
<code>layout_left_padded&lt;padding_stride&gt;</code>, and
<code>Y_sub.stride(1)</code> equals <code>Y.stride(1)</code>.</p>
<p>Let <code>Z</code> be an <code>mdspan</code> with rank at least two
whose layout is <code>layout_left</code>. Let <code>index_type_Z</code>
name the type <code>decltype(Z)::index_type</code>. Let <code>s0</code>
be an object of a type <code>S0</code> such that
<code>is_convertible_v&lt;S0, tuple&lt;index_type_Z, index_type_Z&gt;&gt;</code>
is <code>true</code>, and let <code>s1</code> be an object of a type
<code>S1</code> such that
<code>is_convertible_v&lt;S1, tuple&lt;index_type_Z, index_type_Z&gt;&gt;</code>
is <code>true</code>. In the following code fragment,</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">[]&lt;</span><span class="dt">size_t</span> <span class="op">...</span> Indices<span class="op">&gt;(</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> tuple<span class="op">{(</span>Indices, full_extent<span class="op">)...}</span>;</span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}(</span>make_index_sequence<span class="op">&lt;</span>Z<span class="op">.</span>rank<span class="op">()</span> <span class="op">-</span> <span class="dv">2</span><span class="op">&gt;())</span>;</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> Z_sub <span class="op">=</span> apply<span class="op">(</span> <span class="op">[&amp;](</span>full_extent_t<span class="op">...</span> fe<span class="op">)</span> <span class="op">{</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> submdspan<span class="op">(</span>Z, s0, s1, fe<span class="op">...)</span>;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>, full_extents <span class="op">)</span>;</span></code></pre></div>
<p><code>Z_sub</code> is an <code>mdspan</code> of rank
<code>Z.rank()</code> with layout
<code>layout_left_padded&lt;padding_stride_Z&gt;</code>, where
<code>padding_stride_Z</code> is <code>s0_val1 - s0_val0</code> if
<code>s0</code> is convertible to
<code>tuple&lt;integral_constant&lt;index_type_Z, s0_val0&gt;, integral_constant&lt;index_type_Z, s0_val1&gt;&gt;</code>
with <code>s0_val1</code> greater than to equal to <code>s0_val0</code>.
Also, <code>Z_sub.stride(1)</code> equals <code>Z.stride(1)</code>.</p>
<p>Similarly, let <code>W</code> be an <code>mdspan</code> with rank at
least two whose layout is <code>layout_right</code>. Let
<code>index_type_W</code> name the type
<code>decltype(W)::index_type</code>. Let <code>srm2</code> (“S of rank
minus 2”) be an object of a type <code>Srm2</code> such that
<code>is_convertible_v&lt;Srm2, tuple&lt;index_type_W, index_type_W&gt;&gt;</code>
is <code>true</code>, and let <code>srm1</code> (“S of rank minus 1”) be
an object of a type <code>Srm1</code> such that
<code>is_convertible_v&lt;Srm1, tuple&lt;index_type_W, index_type_W&gt;&gt;</code>
is <code>true</code>. In the following code fragment,</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>  <span class="op">[]&lt;</span><span class="dt">size_t</span> <span class="op">...</span> Indices<span class="op">&gt;(</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> tuple<span class="op">{(</span>Indices, full_extent<span class="op">)...}</span>;</span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">}(</span>make_index_sequence<span class="op">&lt;</span>W<span class="op">.</span>rank<span class="op">()</span> <span class="op">-</span> <span class="dv">2</span><span class="op">&gt;())</span>;</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> W_sub <span class="op">=</span> apply<span class="op">(</span> <span class="op">[&amp;](</span>full_extent_t<span class="op">...</span> fe<span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> submdspan<span class="op">(</span>W, fe<span class="op">...</span>, srm2, srm1<span class="op">)</span>;</span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>, full_extents<span class="op">)</span>;</span></code></pre></div>
<p><code>W_sub</code> is an <code>mdspan</code> of rank
<code>W.rank()</code> with layout
<code>layout_left_padded&lt;padding_stride_W&gt;</code>, where
<code>padding_stride_W</code> is <code>srm1_val1 - srm1_val0</code> if
<code>srm1</code> is convertible to
<code>tuple&lt;integral_constant&lt;index_type_W, srm1_val0&gt;, integral_constant&lt;index_type_W, srm1_val1&gt;&gt;</code>
with <code>srm1_val1</code> greater than to equal to
<code>srm1_val0</code>. Also, <code>W_sub.stride(1)</code> equals
<code>W.stride(1)</code>.</p>
<p>Preservation of these layouts under <code>submdspan</code> is an
important feature for our linear algebra library proposal P1673, because
it means that for existing BLAS and LAPACK use cases, if we start with
one of these layouts, we know that we can implement fast linear algebra
algorithms by calling directly into an optimized C or Fortran BLAS.</p>
<h2 data-number="3.4" id="examples"><span class="header-section-number">3.4</span> Examples<a href="#examples" class="self-link"></a></h2>
<h3 data-number="3.4.1" id="directly-call-c-blas-without-checks"><span class="header-section-number">3.4.1</span> Directly call C BLAS without
checks<a href="#directly-call-c-blas-without-checks" class="self-link"></a></h3>
<p>We show examples before and after this proposal of functions that
compute the matrix-matrix product <span class="math inline"><em>C</em> +  = <em>A</em><em>B</em></span>. The
<code>recursive_matrix_product</code> function computes this product
recursively, by partitioning each of the three matrices into a 2 x 2
block matrix using the <code>partition</code> function. When the
<code>C</code> matrix is small enough,
<code>recursive_matrix_product</code> stops recursing and instead calls
a <code>base_case_matrix_product</code> function with different
overloads for different matrix layouts. If the matrix layouts support
it, <code>base_case_matrix_product</code> can call the C BLAS function
<code>cblas_sgemm</code> directly on the <code>mdspan</code>s’ data.
This is fast if the C BLAS is optimized. Otherwise,
<code>base_case_matrix_product</code> falls back to a slow generic
implementation.</p>
<p>This example is far from ideally optimized, but it hints at the kind
of optimizations that linear algebra computations do in practice.</p>
<p>Common code:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> out_matrix_view <span class="op">=</span> mdspan<span class="op">&lt;</span><span class="dt">float</span>, dextents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span><span class="op">&gt;</span>, Layout<span class="op">&gt;</span>;</span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> in_matrix_view <span class="op">=</span> mdspan<span class="op">&lt;</span><span class="kw">const</span> <span class="dt">float</span>, dextents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span><span class="op">&gt;</span>, Layout<span class="op">&gt;</span>;</span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a><span class="co">// Before this proposal, if Layout is layout_left or layout_right,</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a><span class="co">// the returned mdspan would all be layout_stride.</span></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="co">// After this proposal, the returned mdspan would be</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a><span class="co">// layout_left_padded resp. layout_right_padded.</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> partition<span class="op">(</span>mdspan<span class="op">&lt;</span>ElementType, dextents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span><span class="op">&gt;</span>, Layout<span class="op">&gt;</span> A<span class="op">)</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> M <span class="op">=</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> N <span class="op">=</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A00 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span><span class="dv">0</span>, M <span class="op">/</span> <span class="dv">2</span><span class="op">}</span>, tuple<span class="op">{</span><span class="dv">0</span>, N <span class="op">/</span> <span class="dv">2</span><span class="op">})</span>;</span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A01 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span><span class="dv">0</span>, M <span class="op">/</span> <span class="dv">2</span><span class="op">}</span>, tuple<span class="op">{</span>N <span class="op">/</span> <span class="dv">2</span>, N<span class="op">})</span>;</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A10 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span>M <span class="op">/</span> <span class="dv">2</span>, M<span class="op">}</span>, tuple<span class="op">{</span><span class="dv">0</span>, N <span class="op">/</span> <span class="dv">2</span><span class="op">})</span>;</span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> A11 <span class="op">=</span> submdspan<span class="op">(</span>A, tuple<span class="op">{</span>M <span class="op">/</span> <span class="dv">2</span>, M<span class="op">}</span>, tuple<span class="op">{</span>N <span class="op">/</span> <span class="dv">2</span>, N<span class="op">})</span>;</span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> tuple<span class="op">{</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>    A00, A01,</span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>    A10, A11</span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> recursive_matrix_product<span class="op">(</span>in_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> A,</span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a>  in_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> B, out_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> C<span class="op">)</span></span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Some hardware-dependent constant</span></span>
<span id="cb11-31"><a href="#cb11-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">int</span> recursion_threshold <span class="op">=</span> <span class="dv">16</span>;</span>
<span id="cb11-32"><a href="#cb11-32" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span><span class="op">(</span>std<span class="op">::</span>max<span class="op">(</span>C<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">||</span> C<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">))</span> <span class="op">&lt;=</span> recursion_threshold<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-33"><a href="#cb11-33" aria-hidden="true" tabindex="-1"></a>    base_case_matrix_product<span class="op">(</span>A, B, C<span class="op">)</span>;</span>
<span id="cb11-34"><a href="#cb11-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb11-35"><a href="#cb11-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>C00, C01,</span>
<span id="cb11-36"><a href="#cb11-36" aria-hidden="true" tabindex="-1"></a>          C10, C11<span class="op">]</span> <span class="op">=</span> partition<span class="op">(</span>C<span class="op">)</span>;  </span>
<span id="cb11-37"><a href="#cb11-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>A00, A01,</span>
<span id="cb11-38"><a href="#cb11-38" aria-hidden="true" tabindex="-1"></a>          A10, A11<span class="op">]</span> <span class="op">=</span> partition<span class="op">(</span>A<span class="op">)</span>;  </span>
<span id="cb11-39"><a href="#cb11-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>B00, B01,</span>
<span id="cb11-40"><a href="#cb11-40" aria-hidden="true" tabindex="-1"></a>          B10, B11<span class="op">]</span> <span class="op">=</span> partition<span class="op">(</span>B<span class="op">)</span>;</span>
<span id="cb11-41"><a href="#cb11-41" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A00, B00, C00<span class="op">)</span>;</span>
<span id="cb11-42"><a href="#cb11-42" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A01, B10, C00<span class="op">)</span>;</span>
<span id="cb11-43"><a href="#cb11-43" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A10, B00, C10<span class="op">)</span>;</span>
<span id="cb11-44"><a href="#cb11-44" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A11, B10, C10<span class="op">)</span>;</span>
<span id="cb11-45"><a href="#cb11-45" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A00, B01, C01<span class="op">)</span>;</span>
<span id="cb11-46"><a href="#cb11-46" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A01, B11, C01<span class="op">)</span>;</span>
<span id="cb11-47"><a href="#cb11-47" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A10, B01, C11<span class="op">)</span>;</span>
<span id="cb11-48"><a href="#cb11-48" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A11, B11, C11<span class="op">)</span>;</span>
<span id="cb11-49"><a href="#cb11-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-50"><a href="#cb11-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-51"><a href="#cb11-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-52"><a href="#cb11-52" aria-hidden="true" tabindex="-1"></a><span class="co">// Slow generic implementation</span></span>
<span id="cb11-53"><a href="#cb11-53" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb11-54"><a href="#cb11-54" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> base_case_matrix_product<span class="op">(</span>in_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> A,</span>
<span id="cb11-55"><a href="#cb11-55" aria-hidden="true" tabindex="-1"></a>  in_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> B, out_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;</span> C<span class="op">)</span></span>
<span id="cb11-56"><a href="#cb11-56" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-57"><a href="#cb11-57" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> j <span class="op">=</span> <span class="dv">0</span>; j <span class="op">&lt;</span> C<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>j<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-58"><a href="#cb11-58" aria-hidden="true" tabindex="-1"></a>    <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> i <span class="op">=</span> <span class="dv">0</span>; i <span class="op">&lt;</span> C<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>i<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-59"><a href="#cb11-59" aria-hidden="true" tabindex="-1"></a>      <span class="kw">typename</span> out_matrix_view<span class="op">&lt;</span>Layout<span class="op">&gt;::</span>value_type C_ij<span class="op">{}</span>;</span>
<span id="cb11-60"><a href="#cb11-60" aria-hidden="true" tabindex="-1"></a>      <span class="cf">for</span><span class="op">(</span><span class="dt">size_t</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-61"><a href="#cb11-61" aria-hidden="true" tabindex="-1"></a>        C_ij <span class="op">+=</span> A<span class="op">(</span>i,k<span class="op">)</span> <span class="op">*</span> B<span class="op">(</span>k,j<span class="op">)</span>;</span>
<span id="cb11-62"><a href="#cb11-62" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb11-63"><a href="#cb11-63" aria-hidden="true" tabindex="-1"></a>      C<span class="op">(</span>i,j<span class="op">)</span> <span class="op">+=</span> C_ij;</span>
<span id="cb11-64"><a href="#cb11-64" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-65"><a href="#cb11-65" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-66"><a href="#cb11-66" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>A user might interpret <code>layout_left</code> as “column major,”
and therefore “the natural layout to pass into the BLAS.”</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> base_case_matrix_product<span class="op">(</span>in_matrix_view<span class="op">&lt;</span>layout_left<span class="op">&gt;</span> A,</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  in_matrix_view<span class="op">&lt;</span>layout_left<span class="op">&gt;</span> B, out_matrix_view<span class="op">&lt;</span>layout_left<span class="op">&gt;</span> C<span class="op">)</span></span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>  cblas_sgemm<span class="op">(</span>CblasColMajor, CblasNoTrans, CblasNoTrans,</span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>    C<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>, C<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, <span class="fl">1.0</span><span class="bu">f</span>,</span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a>    A<span class="op">.</span>data_handle<span class="op">()</span>, A<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, B<span class="op">.</span>data_handle<span class="op">()</span>, B<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span>,</span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, C<span class="op">.</span>data_handle<span class="op">()</span>, C<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>However, <code>recursive_matrix_product</code> never gets to use the
<code>layout_left</code> overload of
<code>base_case_matrix_product</code>, because the base case matrices
are always <code>layout_stride</code>.</p>
<p>On discovering this, the author of these functions might be tempted
to write a custom layout for “BLAS-compatible” matrices. However, the
current version of the <code>submdspan</code> proposal
<a href="https://wg21.link/p2630r2">P2630R2</a> forces
<code>partition</code> to return four <code>layout_stride</code> mdspan
if given a <code>layout_left</code> (or <code>layout_right</code>) input
mdspan. This would, in turn, force users of
<code>recursive_matrix_product</code> to commit to a custom layout, if
they want to use the BLAS.</p>
<p>Alternately, the author of these functions could specialize
<code>base_case_matrix_product</code> for <code>layout_stride</code>,
and check whether <code>A.stride(0)</code>, <code>B.stride(0)</code>,
and <code>C.stride(0)</code> are all equal to one before calling
<code>cblas_sgemm</code>. However, that would force extra run-time
checks for a use case that most users might never encounter, because
most users are starting with <code>layout_left</code> matrices or
contiguous submatrices thereof.</p>
<p>After our proposal, the author can specialize
<code>base_case_matrix_product</code> for exactly the layout supported
by the BLAS. They could even get rid of the fall-back implementation if
users never exercise it.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> p<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> base_case_matrix_product<span class="op">(</span>in_matrix_view<span class="op">&lt;</span>layout_left_padded<span class="op">&lt;</span>p<span class="op">&gt;&gt;</span> A,</span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  in_matrix_view<span class="op">&lt;</span>layout_left_padded<span class="op">&lt;</span>p<span class="op">&gt;&gt;</span> B,</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  out_matrix_view<span class="op">&lt;</span>layout_left_padded<span class="op">&lt;</span>p<span class="op">&gt;&gt;</span> C<span class="op">)</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span> <span class="co">// same code as above</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  cblas_sgemm<span class="op">(</span>CblasColMajor, CblasNoTrans, CblasNoTrans,</span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    C<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>, C<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, A<span class="op">.</span>extent<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, <span class="fl">1.0</span><span class="bu">f</span>,</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    A<span class="op">.</span>data_handle<span class="op">()</span>, A<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span>, B<span class="op">.</span>data_handle<span class="op">()</span>, B<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">)</span>,</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a>    <span class="fl">1.0</span><span class="bu">f</span>, C<span class="op">.</span>data_handle<span class="op">()</span>, C<span class="op">.</span>stride<span class="op">(</span><span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="3.4.2" id="overaligned-access"><span class="header-section-number">3.4.2</span> Overaligned access<a href="#overaligned-access" class="self-link"></a></h3>
<p>By combining these new layouts with an accessor that ensures
overaligned access, we can create an mdspan for which the beginning of
every contiguous segment of elements is overaligned by some given
factor. This can enable use of hardware features that require
overaligned memory access.</p>
<p>The following <code>aligned_accessor</code> class template (which
this proposal does <em>not</em> propose to add to the C++ Standard
Library) uses the C++ Standard Library function
<code>assume_aligned</code> to decorate pointer access.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, std<span class="op">::</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> aligned_accessor <span class="op">{</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Even if a pointer p is aligned, p + i might not be.</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> std<span class="op">::</span>default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> reference <span class="op">=</span> ElementType<span class="op">&amp;</span>;</span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Some implementations might have an easier time optimizing</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// if this class applies an attribute to the pointer type.</span></span>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Examples of attributes include</span></span>
<span id="cb14-11"><a href="#cb14-11" aria-hidden="true" tabindex="-1"></a>  <span class="co">// __declspec(align_value(byte_alignment))</span></span>
<span id="cb14-12"><a href="#cb14-12" aria-hidden="true" tabindex="-1"></a>  <span class="co">// and</span></span>
<span id="cb14-13"><a href="#cb14-13" aria-hidden="true" tabindex="-1"></a>  <span class="co">// __attribute__((align_value(byte_alignment))).</span></span>
<span id="cb14-14"><a href="#cb14-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> ElementType<span class="op">*</span>;</span>
<span id="cb14-15"><a href="#cb14-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-16"><a href="#cb14-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb14-17"><a href="#cb14-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-18"><a href="#cb14-18" aria-hidden="true" tabindex="-1"></a>  <span class="co">// A feature of default_accessor that permits</span></span>
<span id="cb14-19"><a href="#cb14-19" aria-hidden="true" tabindex="-1"></a>  <span class="co">// conversion from nonconst to const.</span></span>
<span id="cb14-20"><a href="#cb14-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType, std<span class="op">::</span><span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb14-21"><a href="#cb14-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span></span>
<span id="cb14-22"><a href="#cb14-22" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>is_convertible_v<span class="op">&lt;</span>OtherElementType<span class="op">(*)[]</span>, element_type<span class="op">(*)[]&gt;</span> <span class="op">&amp;&amp;</span></span>
<span id="cb14-23"><a href="#cb14-23" aria-hidden="true" tabindex="-1"></a>    other_byte_alignment <span class="op">==</span> byte_alignment<span class="op">)</span></span>
<span id="cb14-24"><a href="#cb14-24" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb14-25"><a href="#cb14-25" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OtherElementType, other_byte_alignment<span class="op">&gt;)</span> <span class="kw">noexcept</span></span>
<span id="cb14-26"><a href="#cb14-26" aria-hidden="true" tabindex="-1"></a>  <span class="op">{}</span></span>
<span id="cb14-27"><a href="#cb14-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-28"><a href="#cb14-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference</span>
<span id="cb14-29"><a href="#cb14-29" aria-hidden="true" tabindex="-1"></a>  access<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb14-30"><a href="#cb14-30" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>assume_aligned<span class="op">&lt;</span> byte_alignment <span class="op">&gt;(</span>p<span class="op">)[</span>i<span class="op">]</span>;</span>
<span id="cb14-31"><a href="#cb14-31" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-32"><a href="#cb14-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb14-33"><a href="#cb14-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb14-34"><a href="#cb14-34" aria-hidden="true" tabindex="-1"></a>  offset<span class="op">(</span>data_handle_type p, <span class="dt">size_t</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb14-35"><a href="#cb14-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> p <span class="op">+</span> i;</span>
<span id="cb14-36"><a href="#cb14-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb14-37"><a href="#cb14-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>We include some helper functions for making overaligned array
allocations.</p>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span> <span class="kw">operator</span><span class="op">()(</span>ElementType<span class="op">*</span> p<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation_t <span class="op">=</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>ElementType<span class="op">[]</span>, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;&gt;</span>;</span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, std<span class="op">::</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a>allocation_t<span class="op">&lt;</span>ElementType<span class="op">&gt;</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>allocate_raw<span class="op">(</span><span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_elements<span class="op">)</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> num_bytes <span class="op">=</span> num_elements <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span>ElementType<span class="op">)</span>;</span>
<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>  <span class="dt">void</span><span class="op">*</span> ptr <span class="op">=</span> std<span class="op">::</span>aligned_alloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span>;</span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{</span>ptr, delete_raw<span class="op">&lt;</span>ElementType<span class="op">&gt;{}}</span>;</span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Now we can show our example. This 15 x 17 matrix of
<code>float</code> will have extra padding so that every column is
aligned to <code>8 * sizeof(float)</code> bytes. We can use the layout
mapping to determine the required storage size (including padding).
Users can then prove at compile time that they can use special hardware
features that require overaligned access and/or assume that the padding
element at the end of each column is accessible memory.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span><span class="dt">size_t</span> element_alignment <span class="op">=</span> <span class="dv">8</span>;</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  element_alignment <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> layout_type <span class="op">=</span> layout_left_padded<span class="op">&lt;</span>element_alignment<span class="op">&gt;</span>;</span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>layout_type<span class="op">::</span>mapping mapping<span class="op">{</span>dextents<span class="op">&lt;</span><span class="dt">int</span>, <span class="dv">2</span><span class="op">&gt;{</span><span class="dv">15</span>, <span class="dv">17</span><span class="op">}}</span>;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> allocation <span class="op">=</span></span>
<span id="cb16-8"><a href="#cb16-8" aria-hidden="true" tabindex="-1"></a>  allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;(</span>mapping<span class="op">.</span>required_span_size<span class="op">())</span>;</span>
<span id="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-10"><a href="#cb16-10" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> accessor_type <span class="op">=</span> aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;</span>;</span>
<span id="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a>mdspan m<span class="op">{</span>allocation<span class="op">.</span>get<span class="op">()</span>, mapping, accessor_type<span class="op">{}}</span>;</span>
<span id="cb16-12"><a href="#cb16-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a><span class="co">// m_sub has the same layout as m,</span></span>
<span id="cb16-14"><a href="#cb16-14" aria-hidden="true" tabindex="-1"></a><span class="co">// and each column of m_sub has the same overalignment.</span></span>
<span id="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> m_sub <span class="op">=</span> submdspan<span class="op">(</span>m, tuple<span class="op">{</span><span class="dv">0</span>, <span class="dv">11</span><span class="op">}</span>, tuple<span class="op">{</span><span class="dv">1</span>, <span class="dv">13</span><span class="op">})</span>; </span></code></pre></div>
<h2 data-number="3.5" id="alternatives"><span class="header-section-number">3.5</span> Alternatives<a href="#alternatives" class="self-link"></a></h2>
<p>We considered a variant of <code>layout_stride</code> that could
encode any combination of compile-time or run-time strides in the layout
type. This could, for example, use the same mechanism that
<code>extents</code> uses. (The reference implementation calls this
mechanism a “partially static array.”) However, we rejected this
approach as overly complex for our design goals.</p>
<p>First, the goal of <code>layout_{left,right}_padded</code> isn’t to
insist even harder that the compiler bake constants into
<code>mapping::operator()</code> evaluation. The goal is to communicate
compile-time information to <em>users</em>. The most benefit comes not
just from knowing the padding stride at compile time, but also from
knowing that one dimension always uses stride-one (contiguous) storage.
Putting these two pieces of information together lets users apply
compiler annotations like <code>assume_aligned</code>, as in the above
<code>aligned_accessor</code> example. Knowing that one dimension always
uses contiguous storage also tells users that they can pass the mdspan’s
data directly into C or Fortran libraries like the BLAS or LAPACK. Users
can benefit from this even if the padding stride is a run-time
value.</p>
<p>Second, the <code>constexpr</code> annotations in the existing layout
mappings mean that users might be evaluating
<code>layout_stride::mapping::operator()</code> fully at compile time.
The reference mdspan implementation has
<a href="https://github.com/kokkos/mdspan/tree/stable/compilation_tests">several
tests</a> that demonstrate this by using the result of a layout mapping
evaluation in a context where it needs to be known at compile time.</p>
<p>Third, the performance benefit of storing <it>some</it> strides as
compile-time constants goes down as the rank increases, because most of
the strides would end up depending on run-time values anyway. Strided
mdspan generally come from a subview of an existing
<code>layout_left</code> or <code>layout_right</code> mdspan. In that
case, the representation of the strides that preserves the most
compile-time information would be just the original mdspan’s
<code>extents_type</code> object. (Compare to the exposition-only
<em><code>inner-mapping</code></em> which we use in the wording for
<code>layout_{left,right}_padded</code>.) Computing each stride would
then call for a forward (for <code>layout_left</code>) or reverse (for
<code>layout_right</code>) product of the original mdspan’s extents. As
a result, any stride to the right resp. left of a run-time extent would
end up depending on that run-time extent anyway. The larger the rank,
the more strides get “touched” by run-time information.</p>
<p>Fourth, a strided mdspan that can represent layouts as general as
<code>layout_stride</code>, but has entirely compile-time extents
<em>and</em> strides, could be useful for supporting features of a
specific computer architecture. However, these hardware features would
probably have limitations that would prevent them from supporting
general strided layouts anyway. For example, they might require strides
to be a power of two, or they might be limited to specific ranges of
extents or strides. These limitations would call for custom
implementation-specific layouts, not something as general as a
“compile-time <code>layout_stride</code>.”</p>
<h2 data-number="3.6" id="implementation-experience"><span class="header-section-number">3.6</span> Implementation experience<a href="#implementation-experience" class="self-link"></a></h2>
<p>Pull request
<a href="https://github.com/kokkos/mdspan/pull/180">180</a> in the
<a href="https://github.com/kokkos/mdspan/">reference mdspan
implementation</a> implements most of this proposal. Next steps are to
add constructors to the existing layout mappings, and to add
<code>submdspan</code> support for the new layouts.</p>
<h2 data-number="3.7" id="desired-ship-vehicle"><span class="header-section-number">3.7</span> Desired ship vehicle<a href="#desired-ship-vehicle" class="self-link"></a></h2>
<p>C++26 / IS.</p>
<h1 data-number="4" id="wording"><span class="header-section-number">4</span> Wording<a href="#wording" class="self-link"></a></h1>
<blockquote>
<p>Text in blockquotes is not proposed wording, but rather instructions
for generating proposed wording. The � character is used to denote a
placeholder section number which the editor shall determine. First,
apply all wording from P2630R2. (This proposal is a “rebase” atop the
changes proposed by P2630R2.)</p>
</blockquote>
<blockquote>
<p>Add the following feature test macro to <em>[version.syn]</em>,
replacing YYYYMML with the integer literal encoding the appropriate year
(YYYY) and month (MM).</p>
</blockquote>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_mdspan_layout_padded </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;mdspan&gt;</span></span></code></pre></div>
<blockquote>
<p>In Section � <em>[mdspan.syn]</em>, in the synopsis, after
<code>struct layout_stride;</code>, add the following:</p>
</blockquote>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride <span class="op">=</span> dynamic_extent<span class="op">&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_left_padded <span class="op">{</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> mapping;</span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride <span class="op">=</span> dynamic_extent<span class="op">&gt;</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_right_padded <span class="op">{</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> mapping;</span>
<span id="cb18-10"><a href="#cb18-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<blockquote>
<p>After paragraph 1 of <em>[mdspan.layout.policy.overview]</em>, add
the following paragraph 2:</p>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Each specialization of <code>layout_left_padded</code> and
<code>layout_right_padded</code> meets the layout mapping policy
requirements and is a trivial type.</p>
<blockquote>
<p>In Section � <em>[mdspan.layout.left.overview]</em> (“Overview”), add
the following constructor to the <code>layout_left::mapping</code> class
declaration, between the constructor converting from
<code>layout_right::mapping&lt;OtherExtents&gt;</code> and the
constructor converting from
<code>layout_stride::mapping&lt;OtherExtents&gt;</code>:</p>
</blockquote>
<div class="sourceCode" id="cb19"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<blockquote>
<p>In Section � <em>[mdspan.layout.left.cons]</em> (“Constructors”), add
the following between the constructor converting from
<code>layout_right::mapping&lt;OtherExtents&gt;</code> (ending paragraph
8) and the constructor converting from
<code>layout_stride::mapping&lt;OtherExtents&gt;</code> (starting
paragraph 9 before this proposal), then renumber the following
paragraphs in that section accordingly.</p>
</blockquote>
<div class="sourceCode" id="cb20"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Mandates:</em> If</p>
<ul>
<li><p><code>Extents::rank()</code> is greater than one,</p></li>
<li><p><code>Extents::static_extent(0)</code> does not equal
<code>dynamic_extent</code>,</p></li>
<li><p><code>OtherExtents::static_extent(0)</code> does not equal
<code>dynamic_extent</code>, and</p></li>
<li><p><code>other_padding_stride</code> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then <code>Extents::static_extent(0)</code> is a multiple of
<code>other_padding_stride</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p>if <code>extents_type::rank() &gt; 1</code> is <code>true</code>,
then <code>other.stride(1)</code> equals <code>other.extents(0)</code>,
and</p></li>
<li><p><code>other.required_span_size()</code> is representable as a
value of type <code>index_type</code>
(<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em> Direct-non-list-initializes <code>extents_</code> with
<code>other.extents()</code>.</p>
<blockquote>
<p>In Section � <em>[mdspan.layout.right.overview]</em> (“Overview”),
add the following constructor to the <code>layout_right::mapping</code>
class declaration, between the constructor converting from
<code>layout_left::mapping&lt;OtherExtents&gt;</code> and the
constructor converting from
<code>layout_stride::mapping&lt;OtherExtents&gt;</code>.</p>
</blockquote>
<div class="sourceCode" id="cb21"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<blockquote>
<p>In Section � <em>[mdspan.layout.right.cons]</em> (“Constructors”),
add the following between the constructor converting from
<code>layout_left::mapping&lt;OtherExtents&gt;</code> (ending paragraph
8) and the constructor converting from
<code>layout_stride::mapping&lt;OtherExtents&gt;</code> (starting
paragraph 9 before this proposal), then renumber the following
paragraphs in that section accordingly.</p>
</blockquote>
<div class="sourceCode" id="cb22"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Mandates:</em> If</p>
<ul>
<li><p><code>Extents::rank()</code> is greater than one,</p></li>
<li><p><code>Extents::static_extent(Extents::rank() - 1)</code> does not
equal <code>dynamic_extent</code>,</p></li>
<li><p><code>OtherExtents::static_extent(Extents::rank() - 1)</code>
does not equal <code>dynamic_extent</code>, and</p></li>
<li><p><code>other_padding_stride</code> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then <code>Extents::static_extent(Extents::rank() - 1)</code> is a
multiple of <code>other_padding_stride</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p>if <code>extents_type::rank() &gt; 1</code> is <code>true</code>,
then <code>other.stride(extents_type::rank() - 2)</code> equals
<code>other.extents().extent(extents_type::rank() - 1)</code>.</p></li>
<li><p><code>other.required_span_size()</code> is representable as a
value of type <code>index_type</code>
(<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em> Direct-non-list-initializes <code>extents_</code> with
<code>other.extents()</code>.</p>
<blockquote>
<p>In Section � <em>[mdspan.layout.stride.cons]</em>, in paragraph 7
(Remarks for the constructor
<code>layout_stride::mapping(const StridedLayoutMapping&amp;)</code>),
right after the word Remarks, add the following text.</p>
</blockquote>
<p>Let <em><code>is-layout-left-padded-mapping-of</code></em> be the
exposition-only variable template defined as follows.</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-left-padded</em> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>  false_type <span class="op">{}</span>;</span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride<span class="op">&gt;</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-left-padded</em><span class="op">&lt;</span>layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;&gt;</span> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a>  true_type <span class="op">{}</span>;</span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Mapping<span class="op">&gt;</span></span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> <em>is-layout-left-padded-mapping-of</em> <span class="co">// exposition only</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>  <em>is-layout-left-padded</em><span class="op">&lt;</span><span class="kw">typename</span> Mapping<span class="op">::</span>layout_type<span class="op">&gt;::</span>value;</span></code></pre></div>
<p>Let <em><code>is-layout-right-padded-mapping-of</code></em> be the
exposition-only variable template defined as follows.</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-left-padded</em> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  false_type <span class="op">{}</span>;</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride<span class="op">&gt;</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-left-padded</em><span class="op">&lt;</span>layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;&gt;</span> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a>  true_type <span class="op">{}</span>;</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Mapping<span class="op">&gt;</span></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> <em>is-layout-left-padded-mapping-of</em> <span class="co">// exposition only</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a>  <em>is-layout-left-padded</em><span class="op">&lt;</span><span class="kw">typename</span> Mapping<span class="op">::</span>layout_type<span class="op">&gt;::</span>value;</span></code></pre></div>
<blockquote>
<p>In Section � <em>[mdspan.layout.stride.cons]</em>, in paragraph 7
(Remarks for the constructor
<code>layout_stride::mapping(const StridedLayoutMapping&amp;)</code>),
add the following two lines immediately below
<em><code>is-mapping-of</code></em><code>&lt;layout_right, LayoutStrideMapping&gt; ||</code>
and above
<em><code>is-mapping-of</code></em><code>&lt;layout_stride, LayoutStrideMapping&gt; ||</code>:</p>
</blockquote>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><em>is-layout-left-padded-mapping-of</em> <span class="op">&lt;</span>LayoutStrideMapping<span class="op">&gt;</span> <span class="op">||</span></span>
<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><em>is-layout-right-padded-mapping-of</em> <span class="op">&lt;</span>LayoutStrideMapping<span class="op">&gt;</span> <span class="op">||</span></span></code></pre></div>
<blockquote>
<p>After the end of Section � <em>[mdspan.layout.stride]</em>, add the
following:</p>
</blockquote>
<h2 data-number="4.1" id="class-template-layout_left_paddedmapping-mdspan.layout.left_padded"><span class="header-section-number">4.1</span> Class template
<code>layout_left_padded::mapping</code> [mdspan.layout.left_padded]<a href="#class-template-layout_left_paddedmapping-mdspan.layout.left_padded" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>layout_left_padded</code> provides a layout mapping that behaves
like <code>layout_left::mapping</code>, except that the <em>padding
stride</em> <code>stride(1)</code> can be greater than or equal to
<code>extent(0)</code>. Users provide an input padding stride value
either as a <code>size_t</code> template parameter
<code>padding_stride</code> of <code>layout_left_padded</code>, or as a
run-time argument of <code>layout_left_padded::mapping</code>’s
constructor. The padding stride is the least multiple of the input
padding stride value greater than or equal to
<code>extent(0)</code>.</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride<span class="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span>mapping <span class="op">{</span></span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> index_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>index_type;</span>
<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>size_type;</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> rank_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>rank_type;</span>
<span id="cb26-9"><a href="#cb26-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> layout_type <span class="op">=</span> layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;</span>;</span>
<span id="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb26-12"><a href="#cb26-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>actual-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb26-13"><a href="#cb26-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-14"><a href="#cb26-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>inner-extents-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb26-15"><a href="#cb26-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>unpadded-extent-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb26-16"><a href="#cb26-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>inner-mapping-type</em> <span class="op">=</span></span>
<span id="cb26-17"><a href="#cb26-17" aria-hidden="true" tabindex="-1"></a>    layout_left<span class="op">::</span><span class="kw">template</span> mapping<span class="op">&lt;</span><em>inner-extents-type</em><span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb26-18"><a href="#cb26-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-19"><a href="#cb26-19" aria-hidden="true" tabindex="-1"></a>  <em>inner-mapping-type</em> <em>inner-mapping</em>; <span class="co">// exposition only</span></span>
<span id="cb26-20"><a href="#cb26-20" aria-hidden="true" tabindex="-1"></a>  <em>unpadded-extent-type</em> <em>unpadded-extent</em>; <span class="co">// exposition only</span></span>
<span id="cb26-21"><a href="#cb26-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-22"><a href="#cb26-22" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb26-23"><a href="#cb26-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb26-24"><a href="#cb26-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride</em> <span class="op">!=</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb26-25"><a href="#cb26-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb26-26"><a href="#cb26-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride</em> <span class="op">==</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-27"><a href="#cb26-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-28"><a href="#cb26-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb26-29"><a href="#cb26-29" aria-hidden="true" tabindex="-1"></a>  mapping<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb26-30"><a href="#cb26-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-31"><a href="#cb26-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext<span class="op">)</span>;</span>
<span id="cb26-32"><a href="#cb26-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-33"><a href="#cb26-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Size<span class="op">&gt;</span></span>
<span id="cb26-34"><a href="#cb26-34" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext, Size padding_value<span class="op">)</span>;</span>
<span id="cb26-35"><a href="#cb26-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-36"><a href="#cb26-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb26-37"><a href="#cb26-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb26-38"><a href="#cb26-38" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_left<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span>;</span>
<span id="cb26-39"><a href="#cb26-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-40"><a href="#cb26-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb26-41"><a href="#cb26-41" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span>extents_type<span class="op">::</span>rank<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb26-42"><a href="#cb26-42" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span>;</span>
<span id="cb26-43"><a href="#cb26-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-44"><a href="#cb26-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb26-45"><a href="#cb26-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span> <span class="co">/* see below */</span> <span class="op">)</span></span>
<span id="cb26-46"><a href="#cb26-46" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span>;</span>
<span id="cb26-47"><a href="#cb26-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-48"><a href="#cb26-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb26-49"><a href="#cb26-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb26-50"><a href="#cb26-50" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-51"><a href="#cb26-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-52"><a href="#cb26-52" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-53"><a href="#cb26-53" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-54"><a href="#cb26-54" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> std<span class="op">::</span>array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span></span>
<span id="cb26-55"><a href="#cb26-55" aria-hidden="true" tabindex="-1"></a>    strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-56"><a href="#cb26-56" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-57"><a href="#cb26-57" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-58"><a href="#cb26-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-59"><a href="#cb26-59" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb26-60"><a href="#cb26-60" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> index_type <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> idxs<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-61"><a href="#cb26-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-62"><a href="#cb26-62" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_unique<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb26-63"><a href="#cb26-63" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_exhaustive<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-64"><a href="#cb26-64" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_strided<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb26-65"><a href="#cb26-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-66"><a href="#cb26-66" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_unique<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb26-67"><a href="#cb26-67" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> is_exhaustive<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-68"><a href="#cb26-68" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_strided<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb26-69"><a href="#cb26-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-70"><a href="#cb26-70" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type r<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-71"><a href="#cb26-71" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-72"><a href="#cb26-72" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb26-73"><a href="#cb26-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span></span>
<span id="cb26-74"><a href="#cb26-74" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span>,</span>
<span id="cb26-75"><a href="#cb26-75" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> <span class="kw">typename</span> layout_left_padding<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb26-76"><a href="#cb26-76" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Throughout this section, let <code>P_left</code> be the following size
<code>extents_type::rank()</code> parameter pack of
<code>size_t</code>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then the empty
parameter pack;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
else, the parameter pack <code>size_t(1)</code>, <code>size_t(2)</code>,
…, <code>extents_type::rank() - 1</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> If</p>
<ul>
<li><p><code>extents_type::rank()</code> is greater than one,</p></li>
<li><p><code>padding_stride</code> does not equal
<code>dynamic_extent</code>, and</p></li>
<li><p><code>extents_type::static_extent(0)</code> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then the least multiple of <code>padding_stride</code> that is
greater than or equal to <code>extents_type::static_extent(0)</code> is
representable as a value of type <code>size_t</code>, and is
representable as a value of type <code>index_type</code>.</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>actual-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then
<code>padding_stride</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
Else, if</p>
<ul>
<li><p><code>padding_stride</code> does not equal
<code>dynamic_extent</code> and</p></li>
<li><p><code>extents_type::static_extent(0)</code> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then the <code>size_t</code> value which is the least multiple of
<code>padding_stride</code> that is greater than or equal to
<code>extents_type::static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
Otherwise, <code>dynamic_extent</code>.</p></li>
</ul>
<div class="sourceCode" id="cb28"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb28-1"><a href="#cb28-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>inner-extents-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then
<em><code>inner-extents-type</code></em> names the type
<code>extents_type</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
Otherwise, <em><code>inner-extents-type</code></em> names the type
<code>extents&lt;index_type,</code><em><code>actual-padding-stride</code></em><code>, extents_type::static_extent(P_left)...&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb29"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb29-1"><a href="#cb29-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>unpadded-extent-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> If
<code>extents_type::rank()</code> equals zero, then
<em><code>unpadded-extent-type</code></em> names the type
<code>extents&lt;index_type&gt;</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
Otherwise, <em><code>unpadded-extent-type</code></em> names the type
<code>extents&lt;index_type, extents_type::static_extent(0)&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb30"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride == dynamic_extent</em><span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Equivalent to
<code>mapping(extents_type{});</code>.</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb31-1"><a href="#cb31-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Preconditions:</em> If <code>extents_type::rank()</code> is greater
than one and <code>padding_stride</code> does not equal
<code>dynamic_extent</code>, then the least multiple of
<code>padding_stride</code> greater than to equal to
<code>ext.extent(0)</code> is representable as a value of type
<code>index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>ext</code>, if <code>extents_type::rank()</code> is zero or
one; else,</p></li>
<li><p><code>ext.extent(0), ext.extent(P_left)...</code>, if
<code>padding_stride</code> is <code>dynamic_extent</code>;
else,</p></li>
<li><p><code>S_left, ext.extent(P_left)...</code>, where
<code>S_left</code> is the least multiple of <code>padding_stride</code>
greater than or equal to <code>ext.extent(0)</code>; and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>ext.extent(0)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb32"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb32-1"><a href="#cb32-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Size<span class="op">&gt;</span></span>
<span id="cb32-2"><a href="#cb32-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext, Size padding_value<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.1)</a></span>
<code>is_convertible_v&lt;Size, index_type&gt;</code> is
<code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.2)</a></span>
<code>is_nothrow_constructible_v&lt;index_type, Size&gt;</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span> If
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
then</p>
<ul>
<li><p><code>padding_value</code> is representable as a value of type
<code>index_type</code>, and</p></li>
<li><p>the result of converting <code>padding_value</code> to
<code>index_type</code> equals <code>padding_stride</code>.</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span> If
<code>extents_type::rank()</code> is greater than one, then the least
multiple of <code>padding_value</code> greater than to equal to
<code>ext.extent(0)</code> is representable as a value of type
<code>index_type</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>ext</code>, if <code>extents_type::rank()</code> is zero or
one; else,</p></li>
<li><p><code>S_left, ext.extent(P_left)...</code>, where
<code>S_left</code> is the least multiple of <code>padding_value</code>
greater than or equal to <code>ext.extent(0)</code>; and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>ext.extent(0)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb33"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb33-1"><a href="#cb33-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_left<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Mandates:</em> If <code>OtherExtents::rank() &gt; 1</code>,
<em><code>actual-padding-stride</code></em> does not equal
<code>dynamic_extent</code>, and
<code>OtherExtents::static_extent(0)</code> does not equal
<code>dynamic_extent</code>, then
<em><code>actual-padding-stride</code></em> equals
<code>OtherExtents::static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(15.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride == dynamic_extent</code> is <code>false</code>,
then <code>other.stride(1)</code> equals the least multiple of
<code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(0))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(15.2)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code> (<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else</p></li>
<li><p><code>other.stride(1), other.extents().extent(P_left)...</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(0)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb34"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb34-1"><a href="#cb34-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span>extents_type<span class="op">::</span>rank<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb34-3"><a href="#cb34-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">17</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride == dynamic_extent</code> is <code>false</code>,
then <code>other.stride(1)</code> equals the least multiple of
<code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(0))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.2)</a></span> If
<code>extents_type::rank() &gt; 0</code> is <code>true</code>, then
<code>other.stride(0)</code> equals 1;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.3)</a></span> If
<code>extents_type::rank() &gt; 2</code> is <code>true</code>, and then
for all <code>r</code> in the range <span class="math inline">[</span>
<code>2, extents_type::rank()</code><span class="math inline">)</span>,
<code>other.stride(r)</code> equals
<code>other.extents().</code><em><code>fwd-prod-of-extents(r)</code></em><code>/ other.extents().extent(0) * other.stride(1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.4)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code> (<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">20</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(20.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else</p></li>
<li><p><code>other.stride(1), other.extents().extent(P_left)...</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(20.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(0)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span> <span class="co">/* see below */</span> <span class="op">)</span></span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">21</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Mandates:</em>
<code>padding_stride == dynamic_extent || other_padding_stride == dynamic_extent || padding_stride == other_padding_stride</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">23</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
then <code>other.stride(1)</code> equals the least multiple of
<code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extent(0))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.2)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code> (<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">24</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(24.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else</p></li>
<li><p><code>other.stride(1), other.extents().extent(P_left)...</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(24.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(0)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">25</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent to:
<code>extents_type::rank() &gt; 1 &amp;&amp; (padding_stride == dynamic_extent || other_padding_stride == dynamic_extent)</code>.</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb36-1"><a href="#cb36-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">26</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(26.1)</a></span>
<code>extents_type::rank()</code> equals zero or one,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(26.2)</a></span>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">27</a></span>
<em>Precondition:</em> <code>other.required_span_size()</code> is
representable as a value of type <code>index_type</code>
(<em>[basic.fundamental]</em>).</p>
<p><span class="marginalizedparent"><a class="marginalized">28</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(28.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em> with
<code>other.extents()</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(28.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(0)</code>.</p></li>
</ul>
<p><i>[Note:</i> Neither mapping uses the padding stride in the rank-0
or rank-1 case, so the padding stride does not affect either the
constraints or the preconditions. <i>– end note]</i></p>
<div class="sourceCode" id="cb37"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb37-1"><a href="#cb37-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">29</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(29.1)</a></span> If
<code>extents_type::rank()</code> is zero, equivalent to
<code>return extents_type{};</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(29.2)</a></span>
Otherwise, equivalent to
<code>return extents_type(</code><em><code>unpadded-extent_</code></em><code>.extent(0),</code><em><code>inner-mapping</code></em><code>.extent(P_left)...);</code>.</p></li>
</ul>
<div class="sourceCode" id="cb38"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb38-1"><a href="#cb38-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span></span>
<span id="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a>  strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">30</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.strides();</code>.</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">31</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.required_span_size();</code>.</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb40-1"><a href="#cb40-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> i<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">32</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.1)</a></span>
<code>sizeof...(Indices) == Extents::rank()</code> is
<code>true</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.2)</a></span>
<code>(is_convertible_v&lt;Indices, index_type&gt; &amp;&amp; ...)</code>
is <code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.3)</a></span>
<code>(is_nothrow_constructible&lt;index_type, Indices&gt; &amp;&amp; ...)</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">33</a></span>
<em>Precondition:</em>
<code>extents_type::</code><em><code>index-cast</code></em><code>(i)</code>
is a multidimensional index in <code>extents()</code>
(<em>[mdspan.overview]</em>).</p>
<p><span class="marginalizedparent"><a class="marginalized">34</a></span>
<em>Effects:</em> Let P be a parameter pack such that
<code>is_same_v&lt;index_sequence_for&lt;Indices...&gt;, index_sequence&lt;P...&gt;&gt;</code>
is <code>true</code>. Equivalent to:
<code>return ((static_cast&lt;index_type&gt;(i) * stride(P)) + ... + 0);</code>.</p>
<p><i>[Note:</i> Effects are also equivalent to
<code>return</code><em><code>inner-mapping</code></em><code>(i...);</code>,
but only after the Precondition has been applied. <i>– end note]</i></p>
<div class="sourceCode" id="cb41"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb41-1"><a href="#cb41-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_exhaustive<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">35</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.2)</a></span>
else, if neither
<em><code>inner-mapping-type</code></em><code>::static_extent(0)</code>
nor <code>extents_type::static_extent(0)</code> equal
<code>dynamic_extent</code>, then
<em><code>inner-mapping-type</code></em><code>::static_extent(0) == extents_type::static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.3)</a></span>
otherwise, <code>false</code>.</p></li>
</ul>
<div class="sourceCode" id="cb42"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb42-1"><a href="#cb42-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> is_exhaustive<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">36</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(36.1)</a></span> If
<code>extents_type::rank()</code> equals zero, then
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(36.2)</a></span>
else,
<em><code>inner-mapping</code></em><code>.extent(0) ==</code><em><code>unpadded-extent</code></em><code>.extent(0)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb43"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb43-1"><a href="#cb43-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type r<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">37</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.stride(r);</code>.</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb44-1"><a href="#cb44-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb44-2"><a href="#cb44-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span></span>
<span id="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mapping<span class="op">&amp;</span> x,</span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="kw">typename</span> layout_left_padding<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> y<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">38</a></span>
<em>Constraints:</em>
<code>OtherExtents::rank() == extents_type::rank()</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">39</a></span>
<em>Returns:</em> <code>true</code> if</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(39.1)</a></span>
<code>x.extents() == y.extents()</code> is <code>true</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(39.2)</a></span> if
<code>extents_type::rank() &gt; 1</code> is <code>true</code>, then
<code>x.stride(1) == y.stride(1)</code> is <code>true</code>.</p></li>
</ul>
<h2 data-number="4.2" id="class-template-layout_right_paddedmapping-mdspan.layout.right_padded"><span class="header-section-number">4.2</span> Class template
<code>layout_right_padded::mapping</code> [mdspan.layout.right_padded]<a href="#class-template-layout_right_paddedmapping-mdspan.layout.right_padded" class="self-link"></a></h2>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<code>layout_right_padded</code> provides a layout mapping that behaves
like <code>layout_right::mapping</code>, except that the <em>padding
stride</em> <code>stride(rank() - 2)</code> can be greater than or equal
to <code>extent(rank() - 1)</code>. Users provide an input padding
stride value either as a <code>size_t</code> template parameter
<code>padding_stride</code> of <code>layout_right_padded</code>, or as a
run-time argument of <code>layout_right_padded::mapping</code>’s
constructor. The padding stride is the least multiple of the input
padding stride value greater than or equal to
<code>extent(rank() - 1)</code>.</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb45-1"><a href="#cb45-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> padding_stride<span class="op">&gt;</span></span>
<span id="cb45-2"><a href="#cb45-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb45-3"><a href="#cb45-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_right_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span>mapping <span class="op">{</span></span>
<span id="cb45-4"><a href="#cb45-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb45-5"><a href="#cb45-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb45-6"><a href="#cb45-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> index_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>index_type;</span>
<span id="cb45-7"><a href="#cb45-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> size_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>size_type;</span>
<span id="cb45-8"><a href="#cb45-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> rank_type <span class="op">=</span> <span class="kw">typename</span> extents_type<span class="op">::</span>rank_type;</span>
<span id="cb45-9"><a href="#cb45-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> layout_type <span class="op">=</span> layout_right_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;</span>;</span>
<span id="cb45-10"><a href="#cb45-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-11"><a href="#cb45-11" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb45-12"><a href="#cb45-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>actual-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb45-13"><a href="#cb45-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-14"><a href="#cb45-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>inner-extents-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb45-15"><a href="#cb45-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>unpadded-extent-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb45-16"><a href="#cb45-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> <em>inner-mapping-type</em> <span class="op">=</span></span>
<span id="cb45-17"><a href="#cb45-17" aria-hidden="true" tabindex="-1"></a>      layout_right<span class="op">::</span><span class="kw">template</span> mapping<span class="op">&lt;</span><em>inner-extents-type</em><span class="op">&gt;</span>; <span class="co">// exposition only</span></span>
<span id="cb45-18"><a href="#cb45-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-19"><a href="#cb45-19" aria-hidden="true" tabindex="-1"></a>  <em>inner-mapping-type</em> <em>inner-mapping</em>; <span class="co">// exposition only</span></span>
<span id="cb45-20"><a href="#cb45-20" aria-hidden="true" tabindex="-1"></a>  <em>unpadded-extent-type</em> <em>unpadded-extent</em>; <span class="co">// exposition only</span></span>
<span id="cb45-21"><a href="#cb45-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-22"><a href="#cb45-22" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb45-23"><a href="#cb45-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb45-24"><a href="#cb45-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride</em> <span class="op">!=</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb45-25"><a href="#cb45-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb45-26"><a href="#cb45-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride</em> <span class="op">==</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-27"><a href="#cb45-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-28"><a href="#cb45-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb45-29"><a href="#cb45-29" aria-hidden="true" tabindex="-1"></a>  mapping<span class="op">&amp;</span> <span class="kw">operator</span><span class="op">=(</span><span class="kw">const</span> mapping<span class="op">&amp;)</span> <span class="kw">noexcept</span> <span class="op">=</span> <span class="cf">default</span>;</span>
<span id="cb45-30"><a href="#cb45-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-31"><a href="#cb45-31" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext<span class="op">)</span>;</span>
<span id="cb45-32"><a href="#cb45-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-33"><a href="#cb45-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Size<span class="op">&gt;</span></span>
<span id="cb45-34"><a href="#cb45-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext, Size padding_value<span class="op">)</span>;</span>
<span id="cb45-35"><a href="#cb45-35" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-36"><a href="#cb45-36" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb45-37"><a href="#cb45-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb45-38"><a href="#cb45-38" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_right<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span>;</span>
<span id="cb45-39"><a href="#cb45-39" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-40"><a href="#cb45-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb45-41"><a href="#cb45-41" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span>extents_type<span class="op">::</span>rank<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb45-42"><a href="#cb45-42" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span>;</span>
<span id="cb45-43"><a href="#cb45-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-44"><a href="#cb45-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb45-45"><a href="#cb45-45" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span> <span class="co">/* see below */</span> <span class="op">)</span></span>
<span id="cb45-46"><a href="#cb45-46" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span>
<span id="cb45-47"><a href="#cb45-47" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-48"><a href="#cb45-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb45-49"><a href="#cb45-49" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb45-50"><a href="#cb45-50" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-51"><a href="#cb45-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-52"><a href="#cb45-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-53"><a href="#cb45-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-54"><a href="#cb45-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-55"><a href="#cb45-55" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> std<span class="op">::</span>array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span></span>
<span id="cb45-56"><a href="#cb45-56" aria-hidden="true" tabindex="-1"></a>    strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-57"><a href="#cb45-57" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-58"><a href="#cb45-58" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-59"><a href="#cb45-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-60"><a href="#cb45-60" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb45-61"><a href="#cb45-61" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> idxs<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-62"><a href="#cb45-62" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-63"><a href="#cb45-63" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_unique<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb45-64"><a href="#cb45-64" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_exhaustive<span class="op">()</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-65"><a href="#cb45-65" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_strided<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb45-66"><a href="#cb45-66" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-67"><a href="#cb45-67" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_unique<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb45-68"><a href="#cb45-68" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">bool</span> is_exhaustive<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-69"><a href="#cb45-69" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_strided<span class="op">()</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <span class="kw">true</span>; <span class="op">}</span></span>
<span id="cb45-70"><a href="#cb45-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-71"><a href="#cb45-71" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type r<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-72"><a href="#cb45-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb45-73"><a href="#cb45-73" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb45-74"><a href="#cb45-74" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span></span>
<span id="cb45-75"><a href="#cb45-75" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span>,</span>
<span id="cb45-76"><a href="#cb45-76" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> <span class="kw">typename</span> layout_right_padding<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb45-77"><a href="#cb45-77" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
Throughout this section, let <code>P_right</code> be the following size
<code>extents_type::rank()</code> parameter pack of
<code>size_t</code>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then the empty
parameter pack;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
else, the parameter pack <code>size_t(0)</code>, <code>size_t(1)</code>,
…, <code>extents_type::rank() - 2</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> If</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>extents_type::rank()</code> is greater than one,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
<code>extents_type::static_extent(extents_type::rank() - 1)</code> does
not equal <code>dynamic_extent</code>,</p></li>
</ul>
<p>then the least multiple of <code>padding_stride</code> that is
greater than or equal to
<code>extents_type::static_extent(extents_type::rank() - 1)</code> is
representable as a value of type <code>size_t</code>, and is
representable as a value of type <code>index_type</code>.</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb46-1"><a href="#cb46-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>actual-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then
<code>padding_stride</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
Else, if</p>
<ul>
<li><p><code>padding_stride</code> does not equal
<code>dynamic_extent</code> and</p></li>
<li><p><code>extents_type::static_extent(0)</code> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then the <code>size_t</code> value which is the least multiple of
<code>padding_stride</code> that is greater than or equal to
<code>extents_type::static_extent(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
Otherwise, <code>dynamic_extent</code>.</p></li>
</ul>
<div class="sourceCode" id="cb47"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb47-1"><a href="#cb47-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>inner-extents-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one, then
<em><code>inner-extents-type</code></em> names the type
<code>extents_type</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
Otherwise, <em><code>inner-extents-type</code></em> names the type
<code>extents&lt;index_type, extents_type::static_extent(P_right)...,</code><em><code>actual-padding-stride</code></em><code>&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb48"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb48-1"><a href="#cb48-1" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> <em>unpadded-extent-type</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> If
<code>extents_type::rank()</code> equals zero, then
<em><code>unpadded-extent-type</code></em> names the type
<code>extents&lt;index_type&gt;</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
Otherwise, <em><code>unpadded-extent-type</code></em> names the type
<code>extents&lt;index_type, extents_type::static_extent(Extents::rank() - 1)&gt;</code>.</p></li>
</ul>
<div class="sourceCode" id="cb49"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb49-1"><a href="#cb49-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb49-2"><a href="#cb49-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><em>actual-padding-stride == dynamic_extent</em><span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects:</em> Equivalent to
<code>mapping(extents_type{});</code>.</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb50-1"><a href="#cb50-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Preconditions:</em> If <code>extents_type::rank()</code> is greater
than one and <code>padding_stride</code> does not equal
<code>dynamic_extent</code>, then the least multiple of
<code>padding_stride</code> greater than to equal to
<code>ext.extent(extents_type::rank() - 1)</code> is representable as a
value of type <code>index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>ext</code>, if <code>extents_type::rank()</code> is zero or
one; else,</p></li>
<li><p><code>ext.extent(P_right)..., ext.extent(extents_type::rank() - 1)</code>,
if <code>padding_stride</code> is <code>dynamic_extent</code>;
else,</p></li>
<li><p><code>ext.extent(P_right)..., S_right</code>, where
<code>S_right</code> is the least multiple of
<code>padding_stride</code> greater than or equal to
<code>ext.extent(extents_type::rank() - 1)</code>; and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>ext.extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb51"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb51-1"><a href="#cb51-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Size<span class="op">&gt;</span></span>
<span id="cb51-2"><a href="#cb51-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> mapping<span class="op">(</span><span class="kw">const</span> extents_type<span class="op">&amp;</span> ext, Size padding_value<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.1)</a></span>
<code>is_convertible_v&lt;Size, index_type&gt;</code> is
<code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.2)</a></span>
<code>is_nothrow_constructible_v&lt;index_type, Size&gt;</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span> If
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
then</p>
<ul>
<li><p><code>padding_value</code> is representable as a value of type
<code>index_type</code>, and</p></li>
<li><p>the result of converting <code>padding_value</code> to
<code>index_type</code> equals <code>padding_stride</code>.</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.2)</a></span> If
<code>extents_type::rank()</code> is greater than one, then the least
multiple of <code>padding_value</code> greater than to equal to
<code>ext.extent(extents_type::rank() - 1)</code> is representable as a
value of type <code>index_type</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">12</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>ext</code>, if <code>extents_type::rank()</code> is zero or
one; else</p></li>
<li><p><code>ext.extent(P_right)..., S_right</code>, where
<code>S_right</code> is the least multiple of <code>padding_value</code>
greater than or equal to
<code>ext.extent(extents_type::rank() - 1)</code>; and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>ext.extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb52"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb52-1"><a href="#cb52-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb52-2"><a href="#cb52-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb52-3"><a href="#cb52-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_right<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">13</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Mandates:</em> If <code>OtherExtents::rank() &gt; 1</code>,
<em><code>actual-padding-stride</code></em> does not equal
<code>dynamic_extent</code>, and
<code>OtherExtents::static_extent(extents_type::rank() - 1)</code> does
not equal <code>dynamic_extent</code>, then
<em><code>actual-padding-stride</code></em> equals
<code>OtherExtents::static_extent(extents_type::rank() - 1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(15.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
then <code>other.stride(extents_type::rank() - 2)</code> equals the
least multiple of <code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(extents_type::rank() - 1))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(15.2)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code> (<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else,</p></li>
<li><p><code>other.extents().extent(P_right)..., other.stride(extents_type::rank() - 2)</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb53"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb53-1"><a href="#cb53-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb53-2"><a href="#cb53-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span>extents_type<span class="op">::</span>rank<span class="op">()</span> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb53-3"><a href="#cb53-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">17</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride == dynamic_extent</code> is <code>false</code>,
then <code>other.stride(extens_type::rank()-2)</code> equals the least
multiple of <code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(extents_type()::rank()-1))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.2)</a></span> If
<code>extents_type::rank() &gt; 0</code> is <code>true</code>, then
<code>other.stride(extents_type::rank() - 1)</code> equals 1;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.3)</a></span> If
<code>extents_type::rank() &gt; 2</code> is <code>true</code>, then for
all <code>r</code> in the range <span class="math inline">[</span><code>0, extents_type::rank()-2</code><span class="math inline">)</span>, <code>other.stride(r)</code> equals
<code>extents().</code><em><code>rev-prod-of-extents</code></em><code>(r) / other.extents().extent(extents_type::rank()-1) * other.stride(extens_type::rank()-1)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.4)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code> (<em>[basic.fundamental]</em>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">20</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(20.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else,</p></li>
<li><p><code>other.extents().extent(P_right)..., other.stride(extents_type::rank() - 2)</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(20.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb54"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb54-1"><a href="#cb54-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb54-2"><a href="#cb54-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span> <span class="co">/* see below */</span> <span class="op">)</span></span>
<span id="cb54-3"><a href="#cb54-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">21</a></span>
<em>Constraints:</em>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Mandates:</em>
<code>padding_stride == dynamic_extent || other_padding_stride == dynamic_extent || padding_stride == other_padding_stride</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">23</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_stride</code> does not equal <code>dynamic_extent</code>,
then <code>other.stride(extents_type::rank() - 2)</code> equals the
least multiple of <code>padding_stride</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extent(OtherExtents::rank() - 1))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(23.2)</a></span>
<code>other.required_span_size()</code> is representable as a value of
type <code>index_type</code>
(<strong>[basic.fundamental]</strong>).</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">24</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(24.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em>
with:</p>
<ul>
<li><p><code>other.extents()</code>, if
<code>extents_type::rank()</code> is zero or one; else,</p></li>
<li><p><code>other.extents().extent(P_right)..., other.stride(extents_type::rank() - 2)</code>;
and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(24.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, direct-non-list-initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">25</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent to:
<code>extents_type::rank() &gt; 1 &amp;&amp; (padding_stride == dynamic_extent || other_padding_stride == dynamic_extent)</code>.</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb55-1"><a href="#cb55-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb55-2"><a href="#cb55-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(!</span> is_convertible_v<span class="op">&lt;</span>OtherExtents, extents_type<span class="op">&gt;)</span></span>
<span id="cb55-3"><a href="#cb55-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">26</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(26.1)</a></span>
<code>extents_type::rank()</code> equals zero or one, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(26.2)</a></span>
<code>is_constructible_v&lt;extents_type, OtherExtents&gt;</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">27</a></span>
<em>Preconditions:</em> <code>other.required_span_size()</code> is
representable as a value of type <code>index_type</code>
(<strong>[basic.fundamental]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">28</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(28.1)</a></span>
Direct-non-list-initializes <em><code>inner-mapping</code></em> with
<code>other.extents()</code>; and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(28.2)</a></span> if
<code>extents_type::rank()</code> is zero, value-initializes
<em><code>unpadded-extent</code></em>; else, initializes
<em><code>unpadded-extent</code></em> with
<code>other.extents().extent(0)</code>.</p></li>
</ul>
<p><i>[Note:</i> Neither mapping uses the padding stride in the rank-0
or rank-1 case, so the padding stride does not affect either the
constraints or the preconditions. <i>– end note]</i></p>
<div class="sourceCode" id="cb56"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb56-1"><a href="#cb56-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> extents_type extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">29</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(29.1)</a></span> If
<code>extents_type::rank()</code> is zero, equivalent to
<code>return extents_type{};</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(29.2)</a></span>
Otherwise, equivalent to
<code>return extents_type(</code><em><code>inner-mapping</code></em><code>.extent(P_right)...,</code><em><code>unpadded-extent</code></em><code>.extent(extents_type::rank() - 1));</code>.</p></li>
</ul>
<div class="sourceCode" id="cb57"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb57-1"><a href="#cb57-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> std<span class="op">::</span>array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span></span>
<span id="cb57-2"><a href="#cb57-2" aria-hidden="true" tabindex="-1"></a>  strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">30</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.strides();</code>.</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb58-1"><a href="#cb58-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type required_span_size<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">31</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.required_span_size();</code>.</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb59-1"><a href="#cb59-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span><span class="op">...</span> Indices<span class="op">&gt;</span></span>
<span id="cb59-2"><a href="#cb59-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> <span class="kw">operator</span><span class="op">()(</span>Indices<span class="op">...</span> idxs<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">32</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.1)</a></span>
<code>sizeof...(Indices) == Extents::rank()</code> is
<code>true</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.2)</a></span>
<code>(is_convertible_v&lt;Indices, index_type&gt; &amp;&amp; ...)</code>
is <code>true</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(32.3)</a></span>
<code>(is_nothrow_constructible&lt;index_type, Indices&gt; &amp;&amp; ...)</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">33</a></span>
<em>Precondition:</em>
<code>extents_type::</code><em><code>index-cast</code></em><code>(i)</code>
is a multidimensional index in <code>extents()</code>
([mdspan.overview]).</p>
<p><span class="marginalizedparent"><a class="marginalized">34</a></span>
<em>Effects:</em> Let <code>P</code> be a parameter pack such that
<code>is_same_v&lt;index_sequence_for&lt;Indices...&gt;, index_sequence&lt;P...&gt;&gt;</code>
is <code>true</code>. Equivalent to:
<code>return ((static_cast&lt;index_type&gt;(i) * stride(P)) + ... + 0);</code>.</p>
<p><i>[Note:</i> Effects are also equivalent to
<code>return</code><em><code>inner-mapping</code></em><code>(idxs...);</code>,
but only after the Precondition has been applied. <i>– end note]</i></p>
<div class="sourceCode" id="cb60"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb60-1"><a href="#cb60-1" aria-hidden="true" tabindex="-1"></a><span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">bool</span> is_always_exhaustive<span class="op">()</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">35</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.1)</a></span> If
<code>extents_type::rank()</code> equals zero or one,
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.2)</a></span>
else, if neither
<em><code>inner-mapping-type</code></em><code>::static_extent(extents_type::rank() - 1)</code>
nor <code>extents_type::static_extent(extents_type::rank() - 1)</code>
equal <code>dynamic_extent</code>, then
<em><code>inner-mapping-type</code></em><code>::static_extent(extents_type::rank() - 1) == extents_type::static_extent(extents_type::rank() - 1)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(35.3)</a></span>
otherwise, <code>false</code>.</p></li>
</ul>
<div class="sourceCode" id="cb61"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb61-1"><a href="#cb61-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> is_exhaustive<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">36</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(36.1)</a></span> If
<code>extents_type::rank()</code> equals zero, then
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(36.2)</a></span>
else,
<em><code>inner-mapping</code></em><code>.extent(extents_type::rank() - 1) ==</code><em><code>unpadded-extent</code></em><code>.extent(extents_type::rank() - 1)</code>.</p></li>
</ul>
<div class="sourceCode" id="cb62"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb62-1"><a href="#cb62-1" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> index_type stride<span class="op">(</span>rank_type r<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">37</a></span>
<em>Effects:</em> Equivalent to <code>return</code>
<em><code>inner-mapping</code></em><code>.stride(r);</code>.</p>
<div class="sourceCode" id="cb63"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb63-1"><a href="#cb63-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> other_padding_stride, <span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb63-2"><a href="#cb63-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="dt">bool</span> <span class="kw">operator</span><span class="op">==(</span></span>
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mapping<span class="op">&amp;</span> x,</span>
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> <span class="kw">typename</span> layout_right_padding<span class="op">&lt;</span>other_padding_stride<span class="op">&gt;::</span>mapping<span class="op">&lt;</span>OtherExtents<span class="op">&gt;&amp;</span> y<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">38</a></span>
<em>Constraints:</em>
<code>OtherExtents::rank() == extents_type::rank()</code> is
<code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">39</a></span>
<em>Returns:</em> <code>true</code> if</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(39.1)</a></span>
<code>x.extents() == y.extents()</code> is <code>true</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(39.2)</a></span> if
<code>extents_type::rank() &gt; 1</code> is <code>true</code>, then
<code>x.stride(extents_type::rank() - 2) == y.stride(extents_type::rank() - 2)</code>
is <code>true</code>.</p></li>
</ul>
<h2 data-number="4.3" id="layout-specializations-of-submdspan_mapping-mdspan.submdspan.mapping"><span class="header-section-number">4.3</span> Layout specializations of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping]<a href="#layout-specializations-of-submdspan_mapping-mdspan.submdspan.mapping" class="self-link"></a></h2>
<blockquote>
<p>At the top of Section � [mdspan.submdspan.mapping] (“Layout
specializations of <code>submdspan_mapping</code>”), before paragraph 1,
add the following to the end of the synopsis of specializations.</p>
</blockquote>
<div class="sourceCode" id="cb64"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb64-1"><a href="#cb64-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents, std<span class="op">::</span><span class="dt">size_t</span> padding_stride, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb64-2"><a href="#cb64-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>Extents<span class="op">&gt;&amp;</span> src, </span>
<span id="cb64-4"><a href="#cb64-4" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see below */</span>;</span>
<span id="cb64-5"><a href="#cb64-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb64-6"><a href="#cb64-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents, std<span class="op">::</span><span class="dt">size_t</span> padding_stride, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb64-7"><a href="#cb64-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb64-8"><a href="#cb64-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>Extents<span class="op">&gt;&amp;</span> src, </span>
<span id="cb64-9"><a href="#cb64-9" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="op">-&gt;</span> <span class="co">/* see below */</span>;</span></code></pre></div>
<blockquote>
<p>In paragraph 7 (the “Returns” clause) of Section �
[mdspan.submdspan.mapping] (“Layout specializations of
submdspan_mapping”), replace (7.3) (the <code>layout_stride</code>
fall-back return type) with the following.</p>
</blockquote>
<p><span class="marginalizedparent"><a class="marginalized">(9.4)</a></span>
<code>submdspan_mapping_result{layout_left_padded&lt;Extents::static_extent(0)&gt;::mapping(sub_ext, src.extent(0)), offset}</code>
if</p>
<ul>
<li><p><code>decltype(src)::layout_type</code> is
<code>layout_left</code>; and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span><code>1, SubExtents::rank()-1</code><span class="math inline">)</span>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is
<code>full_extent_t</code>; and</p></li>
<li><p><code>is_convertible_v&lt;</code> <span class="math inline"><em>S</em><sub>0</sub></span>
<code>, tuple&lt;index_type, index_type&gt;&gt;</code> is
<code>true</code>; and</p></li>
<li><p>for <code>k</code> equal to <code>SubExtents::rank()-1</code>,
<code>is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>; otherwise</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">(9.5)</a></span>
<code>submdspan_mapping_result{layout_right_padded&lt;Extents::static_extent(0)&gt;::template mapping(sub_ext, src.extent(0)), offset}</code>
if</p>
<ul>
<li><p><code>decltype(src)::layout_type</code> is
<code>layout_right</code>; and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span><code>Extents::rank() - SubExtents::rank() + 1, Extents.rank() - 1</code><span class="math inline">)</span>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is
<code>full_extent_t</code>; and</p></li>
<li><p>for <code>k</code> equal to <code>Extents::rank() - 1</code>
<code>is_convertible_v&lt;</code> <span class="math inline"><em>S</em><sub><em>k</em></sub></span>
<code>, tuple&lt;index_type, index_type&gt;&gt;</code> is
<code>true</code>; and</p></li>
<li><p>for <code>k</code> equal to
<code>SubExtents::rank() - SubExtents::rank()</code>,
<code>is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>; otherwise</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">(9.6)</a></span>
<code>submdspan_mapping_result{layout_left_padded&lt;dynamic_extent&gt;::mapping(sub_ext, src.extent(0)), offset}</code>
if</p>
<ul>
<li><p><code>decltype(src)::layout_type</code> is a specialization of
<code>layout_left_padded</code>; and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span><code>1, SubExtents::rank()-1</code><span class="math inline">)</span>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is
<code>full_extent_t</code>; and</p></li>
<li><p><code>is_convertible_v&lt;</code> <span class="math inline"><em>S</em><sub>0</sub></span>
<code>, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub>0</sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>; and</p></li>
<li><p>for <code>k</code> equal to <code>SubExtents::rank()-1</code>,
<code>is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;</code><span class="math inline"><em>S</em><sub><em>k</em></sub></span><code>, full_extent_t&gt;</code>
is <code>true</code>; otherwise</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">(9.7)</a></span>
<code>submdspan_mapping_result{layout_right_padded&lt;dynamic_extent&gt;::template mapping(sub_ext, src.extent(0)), offset}</code>
if</p>
<ul>
<li><p><code>decltype(src)::layout_type</code> is a specialization of
<code>layout_right_padded</code>; and</p></li>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span><code>Extents::rank() - SubExtents::rank() + 1, Extents.rank() - 1</code><span class="math inline">)</span>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is
<code>full_extent_t</code>; and</p></li>
<li><p>for <code>k</code> equal to <code>Extents::rank() - 1</code>
<code>is_convertible_v&lt;</code> <span class="math inline"><em>S</em><sub><em>k</em></sub></span>
<code>, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;</code>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span>
<code>, full_extent_t&gt;</code> is <code>true</code>; and</p></li>
<li><p>for <code>k</code> equal to
<code>SubExtents::rank() - SubExtents::rank()</code>,
<code>is_convertible_v&lt;S_k, tuple&lt;index_type, index_type&gt;&gt; || is_convertible_v&lt;S_k, full_extent_t&gt;</code>
is <code>true</code>; otherwise</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">(9.8)</a></span>
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p>
<h2 data-number="4.4" id="layout-specializations-of-submdspan_offset-mdspan.submdspan.offset"><span class="header-section-number">4.4</span> Layout specializations of
<code>submdspan_offset</code> [mdspan.submdspan.offset]<a href="#layout-specializations-of-submdspan_offset-mdspan.submdspan.offset" class="self-link"></a></h2>
<blockquote>
<p>At the top of Section � [mdspan.submdspan.offset] (“Layout
specializations of <code>submdspan_offset</code>”), before paragraph 1,
add the following to the end of the synopsis of specializations. (Note
that all the specializations of <code>submdspan_offset</code> share the
same wording.)</p>
</blockquote>
<div class="sourceCode" id="cb65"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb65-1"><a href="#cb65-1" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents, std<span class="op">::</span><span class="dt">size_t</span> padding_stride, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb65-2"><a href="#cb65-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">size_t</span> submdspan_offset<span class="op">(</span></span>
<span id="cb65-3"><a href="#cb65-3" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> layout_left_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>Extents<span class="op">&gt;&amp;</span> src, </span>
<span id="cb65-4"><a href="#cb65-4" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span>;</span>
<span id="cb65-5"><a href="#cb65-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb65-6"><a href="#cb65-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents, std<span class="op">::</span><span class="dt">size_t</span> padding_stride, <span class="kw">class</span><span class="op">...</span> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb65-7"><a href="#cb65-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">size_t</span> submdspan_offset<span class="op">(</span></span>
<span id="cb65-8"><a href="#cb65-8" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> layout_right_padded<span class="op">&lt;</span>padding_stride<span class="op">&gt;::</span><span class="kw">template</span> mapping<span class="op">&lt;</span>Extents<span class="op">&gt;&amp;</span> src, </span>
<span id="cb65-9"><a href="#cb65-9" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span>;</span></code></pre></div>
</div>
</div>
</body>
</html>
