<!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-12-05" />
  <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 { 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: #00AA00}
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:image/vnd.microsoft.icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" 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-12-05</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>
      Christian Trott (Sandia National Laboratories)<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.gov</a>&gt;<br>
      Mark Hoemmen (NVIDIA)<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</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>
      Nicolas Morales (Sandia National Laboratories)<br>&lt;<a href="mailto:nmmoral@sandia.gov" class="email">nmmoral@sandia.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>
<li><a href="#revision-3" id="toc-revision-3"><span class="toc-section-number">2.4</span> Revision 3</a></li>
<li><a href="#revision-4" id="toc-revision-4"><span class="toc-section-number">2.5</span> Revision 4</a></li>
<li><a href="#revision-5" id="toc-revision-5"><span class="toc-section-number">2.6</span> Revision 5</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="#consider-rank-1-case-as-submdspan-of-rank-2" id="toc-consider-rank-1-case-as-submdspan-of-rank-2"><span class="toc-section-number">3.2.3</span> Consider rank-1 case as
<code>submdspan</code> of rank-2</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.4</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.5</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.6</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.7</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.8</span> Conversion from
<code>layout_stride</code> to <code>layout_left_padded</code></a></li>
<li><a href="#design-change-from-r2-to-r3-extents-return-type" id="toc-design-change-from-r2-to-r3-extents-return-type"><span class="toc-section-number">3.2.9</span> Design change from R2 to R3:
<code>extents()</code> return type</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="#design-alternatives" id="toc-design-alternatives"><span class="toc-section-number">3.5</span> Design alternatives</a>
<ul>
<li><a href="#strided-layout-with-compile-time-strides" id="toc-strided-layout-with-compile-time-strides"><span class="toc-section-number">3.5.1</span> Strided layout with compile-time
strides</a></li>
<li><a href="#lewg-r2-polls-discussion" id="toc-lewg-r2-polls-discussion"><span class="toc-section-number">3.5.2</span> LEWG R2 polls
discussion</a></li>
<li><a href="#nest-the-new-policies-in-corresponding-existing-ones" id="toc-nest-the-new-policies-in-corresponding-existing-ones"><span class="toc-section-number">3.5.3</span> Nest the new policies in
corresponding existing ones</a></li>
<li><a href="#layout-mapping-conversion-customization-point" id="toc-layout-mapping-conversion-customization-point"><span class="toc-section-number">3.5.4</span> Layout mapping conversion
customization point</a></li>
</ul></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.leftpadded" id="toc-class-template-layout_left_paddedmapping-mdspan.layout.leftpadded"><span class="toc-section-number">4.1</span> Class template
<code>layout_left_padded::mapping</code> [mdspan.layout.leftpadded]</a>
<ul>
<li><a href="#overview-mdspan.layout.leftpadded.overview" id="toc-overview-mdspan.layout.leftpadded.overview"><span class="toc-section-number">4.1.1</span> Overview
[mdspan.layout.leftpadded.overview]</a></li>
<li><a href="#constructors-mdspan.layout.leftpadded.cons" id="toc-constructors-mdspan.layout.leftpadded.cons"><span class="toc-section-number">4.1.2</span> Constructors
[mdspan.layout.leftpadded.cons]</a></li>
<li><a href="#observers-mdspan.layout.leftpadded.obs" id="toc-observers-mdspan.layout.leftpadded.obs"><span class="toc-section-number">4.1.3</span> Observers
[mdspan.layout.leftpadded.obs]</a></li>
</ul></li>
<li><a href="#class-template-layout_right_paddedmapping-mdspan.layout.rightpadded" id="toc-class-template-layout_right_paddedmapping-mdspan.layout.rightpadded"><span class="toc-section-number">4.2</span> Class template
<code>layout_right_padded::mapping</code>
[mdspan.layout.rightpadded]</a>
<ul>
<li><a href="#overview-mdspan.layout.rightpadded.overview" id="toc-overview-mdspan.layout.rightpadded.overview"><span class="toc-section-number">4.2.1</span> Overview
[mdspan.layout.rightpadded.overview]</a></li>
<li><a href="#constructors-mdspan.layout.rightpadded.cons" id="toc-constructors-mdspan.layout.rightpadded.cons"><span class="toc-section-number">4.2.2</span> Constructors
[mdspan.layout.rightpadded.cons]</a></li>
<li><a href="#observers-mdspan.layout.rightpadded.obs" id="toc-observers-mdspan.layout.rightpadded.obs"><span class="toc-section-number">4.2.3</span> Observers
[mdspan.layout.rightpadded.obs]</a></li>
</ul></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>
</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>static-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>
<h2 data-number="2.4" id="revision-3"><span class="header-section-number">2.4</span> Revision 3<a href="#revision-3" class="self-link"></a></h2>
<p>Revision 3 to be submitted sometime after 2023-07-09.</p>
<ul>
<li><p>Update P2630 (<code>submdspan</code>) revision number to
R3.</p></li>
<li><p>Add references to P2897 (<code>aligned_accessor</code>).</p></li>
<li><p>Change return type of the padded layout mappings’
<code>extents()</code> member functions from <code>extents_type</code>
to <code>const extents_type&amp;</code>, to make them consistent with
the existing layout mapping requirements. As a result, change the padded
layout mappings to include an exposition-only
<em><code>actual-extents</code></em> member, so that
<code>extents()</code> can return a valid reference. Thanks to Oliver
Lee (oliverzlee@gmail.com) for an excellent discussion!</p></li>
<li><p>Add design discussion requested by LEWG on 2023/03/28 relating to
the results of the two polls.</p></li>
<li><p>Add design discussion about <code>required_span_size()</code> of
rank-1 padded layout mdspan.</p></li>
<li><p>Update implementation experience with new pull request
number.</p></li>
<li><p>Change converting constructors from
<code>layout_{left,right}_padded&lt;ps&gt;::mapping&lt;OE&gt;</code>,
and <code>operator==</code> taking that type, to use a constraint
instead of overloading. This helps with type deduction in practice. As a
result, we needed a way to get the <code>padding_stride</code> template
argument of a mapping. We found it easiest to do this by adding a
<code>static constexpr size_t padding_stride</code> public member to the
mapping. Another approach would have been to introduce an
exposition-only trait, but we think the public member would be more
generally useful.</p></li>
<li><p>Add Nic Morales as a coauthor.</p></li>
</ul>
<h2 data-number="2.5" id="revision-4"><span class="header-section-number">2.5</span> Revision 4<a href="#revision-4" class="self-link"></a></h2>
<ul>
<li><p>bring wording in-line with layouts in the ISO C++ standard
draft</p></li>
<li><p>redo submdspan wording</p>
<ul>
<li><p>in particular redo the specialization section for
<code>submdspan_mapping</code></p></li>
<li><p>split by layout type</p></li>
<li><p>pull common items for all layouts into a <em>Common</em>
subsection</p></li>
</ul></li>
</ul>
<h2 data-number="2.6" id="revision-5"><span class="header-section-number">2.6</span> Revision 5<a href="#revision-5" class="self-link"></a></h2>
<ul>
<li><p>Make change requested in 2023/11/09 LEWG poll: “Modify P2642R4
(Padded mdspan layouts) by removing the feature test macro and bumping
the <code>__cpp_lib_submdspan</code> macro….”</p></li>
<li><p>Remove “rebase on top of P2630R3” wording, since P2630 has been
merged into the current C++ Working Draft. Update current C++ Working
Draft reference to the latest at the time of publication,
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4964.pdf">N4964</a>.</p></li>
<li><p>Update non-wording text and implementation experience.</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, P1673, 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 have replaced the <code>layout_blas_general</code> layout in
earlier versions of our <a href="https://wg21.link/p1673">P1673</a>
proposal 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 include <code>submdspan</code>
integration in this proposal.</p>
<h3 data-number="3.2.3" id="consider-rank-1-case-as-submdspan-of-rank-2"><span class="header-section-number">3.2.3</span> Consider rank-1 case as
<code>submdspan</code> of rank-2<a href="#consider-rank-1-case-as-submdspan-of-rank-2" class="self-link"></a></h3>
<p>One review asked why <code>required_span_size()</code> of
<code>layout_right_padded&lt;4&gt;::mapping&lt;extents&lt;size_t, 1, 3&gt;&gt;</code>
is 4 instead of 3. We made that choice for the following reasons.</p>
<ol type="1">
<li><p>Overalignment should imply correct SIMD access as well as pointer
alignment</p></li>
<li><p>Consistency of the rank-1 case with <code>submdspan</code> of a
rank-2 mdspan</p></li>
</ol>
<p>Regarding (1), an important design goal is use with explicit SIMD
instructions. This means that we need to be able to access groups of 4
elements at a time. This is also consistent with
<code>assume_aligned&lt;N, T&gt;</code>. That doesn’t just return a
pointer <code>p</code> such that
<code>reinterpret_cast&lt;uintptr_t&gt;(p)</code> is divisible by
<code>N</code>; it returns a pointer to an object of type <code>T</code>
whose alignment is at least <code>N</code> bytes.
<code>layout_right_padded&lt;4&gt;::mapping&lt;extents&lt;size_t, M, 3&gt;&gt;</code>
for <code>M</code> in [1, 4] means “assume that each row is a
<code>T[4]</code> with byte alignment <code>4 * sizeof(T)</code>.”</p>
<p>Regarding (2), the idea is that the rank-2 or more case (with more
than one row, column, etc.) controls the behavior of the rank-1 case.
The rank-1 (or rank-2 but single row or column) case should act like a
<code>submdspan</code> of the rank-2 case. It helps to understand that
we intend to support the BLAS and LAPACK. For example,
<code>layout_left_padded&lt;4&gt;::mapping&lt;extents&lt;size_t, 3, 3&gt;&gt;</code>
means “a view of the top 3 rows of a 4 x 3 matrix” (LDA = 4, M = 3, N =
3, where LDA is a BLAS abbreviation meaning “leading dimension [of the
matrix] A”). (This example switches to <code>layout_left_padded</code>
just because the Fortran BLAS only supports column-major order, but the
analogous idea applies to the <code>layout_right_padded</code> case that
the C BLAS also supports.) Taking a <code>submdspan</code> of the
leftmost column results in a rank-1 mdspan with a
<code>required_span_size()</code> of 4 elements.</p>
<h3 data-number="3.2.4" id="design-change-from-r0-to-r1"><span class="header-section-number">3.2.4</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.5" id="padding-stride-equality-for-layout-mapping-conversions"><span class="header-section-number">3.2.5</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.6" id="new-layout-mapping-constructors-in-r2"><span class="header-section-number">3.2.6</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.7" id="conversion-from-layout_left-to-layout_left_padded"><span class="header-section-number">3.2.7</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.8" id="conversion-from-layout_stride-to-layout_left_padded"><span class="header-section-number">3.2.8</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>
<h3 data-number="3.2.9" id="design-change-from-r2-to-r3-extents-return-type"><span class="header-section-number">3.2.9</span> Design change from R2 to R3:
<code>extents()</code> return type<a href="#design-change-from-r2-to-r3-extents-return-type" class="self-link"></a></h3>
<p>In revisions of this proposal up to and including R2, the new layout
mappings’ <code>extents()</code> member functions both had return type
<code>extents_type</code>. That is, they both returned by value. We did
this deliberately, so that we could specify the layout mappings in terms
of the behavior of <code>layout_left::mapping</code> resp.
<code>layout_right::mapping</code> with a padded <code>extents</code>
object, without needing to store the “original” <code>extents</code>.
However, we realized after the publication of R2 that this does not
respect the existing layout mapping requirements in paragraph 6 of
<em>[mdspan.layout.reqmnts]</em>. This specifies the return type of
<code>m.extents()</code> for every layout mapping as
<code>const extents_type&amp;</code>. That is, <code>extents()</code>
must always return by const reference.</p>
<p>We considered changing the layout mapping requirements to permit
layout mappings to return either <code>extents_type</code> or
<code>const extents_type&amp;</code>. However, we realized that
<em>[mdspan.mdspan]</em> specifies that mdspan’s <code>extent(r)</code>
member function returns
<em><code>map_</code></em><code>.extents().extent(r)</code>. Letting a
layout mapping’s <code>extents()</code> create and return a temporary
could make mdspan’s <code>extent(r)</code> unexpectedly expensive. It
should be always be cheap to get a single extent from an mdspan, because
it’s a common multidimensional array idiom to write nested
<code>for</code> loops over each extent.</p>
<p>Our specification in <em>[mdspan.mdspan]</em> that mdspan’s
<code>extent(r)</code> returns
<em><code>map_</code></em><code>.extents().extent(r)</code> was also
deliberate. It expresses two design choices. First, requiring mdspan to
get its extents from its layout mapping (that is, specifying mdspan’s
<code>extents()</code> to return
<em><code>map_</code></em><code>.extents()</code>) ensures that an
mdspan is nothing more that the composition of its data handle, layout
mapping, and accessor. The layout mapping controls the extents; an
mdspan cannot have “its own extents” that differ from those in its
layout mapping. Second, not including <code>extents(r)</code> in the
layout mapping means that a layout mapping also cannot have “its own
extents” that differ from what <code>extents()</code> returns. Those two
choices mean that the following code is well formed and does not trigger
an <code>assert</code> for any mdspan <code>x</code>.</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="co">// An mdspan&#39;s extents are its mapping&#39;s extents.</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> mapping_type <span class="op">=</span> <span class="kw">decltype</span><span class="op">(</span>x<span class="op">)::</span>mapping_type;</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> extents_type <span class="op">=</span> mapping_type<span class="op">::</span>extents_type;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>x<span class="op">)::</span>extents_type, extents_type<span class="op">&gt;)</span>;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>x<span class="op">.</span>extents<span class="op">()</span> <span class="op">==</span> x<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">())</span>;</span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="co">// A mapping&#39;s extent(r) must agree with its extents().</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> e <span class="op">=</span> <span class="op">[&amp;]</span> <span class="op">&lt;</span><span class="dt">size_t</span><span class="op">...</span> Indices<span class="op">&gt;</span> <span class="op">(</span>std<span class="op">::</span>index_sequence<span class="op">&lt;</span>Indices<span class="op">...&gt;)</span> <span class="op">{</span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a>    <span class="kw">using</span> index_type <span class="op">=</span> extents_type<span class="op">::</span>index_type;</span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> extents<span class="op">&lt;</span>index_type, x<span class="op">.</span>static_extent<span class="op">(</span>Indices<span class="op">)...&gt;{</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>      x<span class="op">.</span>mapping<span class="op">().</span>extent<span class="op">(</span>Indices<span class="op">)...</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>;</span>
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="op">(</span>std<span class="op">::</span>make_index_sequence<span class="op">&lt;</span>x<span class="op">.</span>rank<span class="op">()&gt;())</span>;</span>
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>is_same_v<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>e<span class="op">)</span>, extents_type<span class="op">&gt;)</span>;</span>
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a><span class="ot">assert</span><span class="op">(</span>e <span class="op">==</span> x<span class="op">.</span>mapping<span class="op">().</span>extents<span class="op">())</span>;</span></code></pre></div>
<p>All these design choices add up to the padded layout mappings needing
to return <code>const extents_type&amp;</code> from
<code>extents()</code>. This means that we cannot use R2’s wording
approach of having <code>extents()</code> return a temporary
<code>extents</code> object. (Lifetime extension does not apply to a
temporary created in and returned from a <code>return</code> statement.)
Our wording fix in subsequent revisions is minimal: we add a new
exposition-only <em><code>actual-extents</code></em> member of type
<code>extents_type</code> to both of the padded mappings. However, this
is not meant to suggest that implementations should take this approach.
Instead of following the wording by using a nested
<code>layout_left::mapping</code> resp.
<code>layout_right::mapping</code> with a padded extents object, they
could just reimplement the padded mappings as special cases of
<code>layout_stride</code>. That way, each mapping would only store one
<code>extents_type</code> object, and <code>extents()</code> would
return a const reference to that object.</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> (see
<a href="https://wg21.link/p2630">P2630</a>, which was accepted into the
C++ Working Draft for C++26) 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="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> S0, <span class="kw">class</span> S1<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>S0,</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>S1,</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> left_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, S0 s0, S1 s1<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, s0, s1, fe<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>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="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">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="cb8-2"><a href="#cb8-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="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="kw">requires</span><span class="op">(</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>Srm2,</span>
<span id="cb8-5"><a href="#cb8-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="cb8-6"><a href="#cb8-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="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a>  is_convertible_v<span class="op">&lt;</span>Srm1,</span>
<span id="cb8-8"><a href="#cb8-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="cb8-9"><a href="#cb8-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="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> right_submatrix<span class="op">(</span></span>
<span id="cb8-12"><a href="#cb8-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="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> full_extents <span class="op">=</span></span>
<span id="cb8-15"><a href="#cb8-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="cb8-16"><a href="#cb8-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="cb8-17"><a href="#cb8-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="cb8-18"><a href="#cb8-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="cb8-19"><a href="#cb8-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="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span>, full_extents<span class="op">)</span>;</span>
<span id="cb8-21"><a href="#cb8-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="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>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="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> 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="cb9-7"><a href="#cb9-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="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>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="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>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="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> 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="cb10-7"><a href="#cb10-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="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>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="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">auto</span> full_extents <span class="op">=</span></span>
<span id="cb11-2"><a href="#cb11-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="cb11-3"><a href="#cb11-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="cb11-4"><a href="#cb11-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="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-6"><a href="#cb11-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="cb11-7"><a href="#cb11-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="cb11-8"><a href="#cb11-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 (which
was accepted into the C++ Working Draft for C++26). 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="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="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb12-2"><a href="#cb12-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="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-4"><a href="#cb12-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="cb12-5"><a href="#cb12-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="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-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="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="co">// the returned mdspan would all be layout_stride.</span></span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="co">// After this proposal, the returned mdspan would be</span></span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="co">// layout_left_padded resp. layout_right_padded.</span></span>
<span id="cb12-11"><a href="#cb12-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="cb12-12"><a href="#cb12-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="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-14"><a href="#cb12-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="cb12-15"><a href="#cb12-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="cb12-16"><a href="#cb12-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="cb12-17"><a href="#cb12-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="cb12-18"><a href="#cb12-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="cb12-19"><a href="#cb12-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="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> tuple<span class="op">{</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>    A00, A01,</span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>    A10, A11</span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>;</span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-26"><a href="#cb12-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="cb12-27"><a href="#cb12-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="cb12-28"><a href="#cb12-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="cb12-29"><a href="#cb12-29" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Some hardware-dependent constant</span></span>
<span id="cb12-31"><a href="#cb12-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="cb12-32"><a href="#cb12-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="cb12-33"><a href="#cb12-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="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>C00, C01,</span>
<span id="cb12-36"><a href="#cb12-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="cb12-37"><a href="#cb12-37" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>A00, A01,</span>
<span id="cb12-38"><a href="#cb12-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="cb12-39"><a href="#cb12-39" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>B00, B01,</span>
<span id="cb12-40"><a href="#cb12-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="cb12-41"><a href="#cb12-41" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A00, B00, C00<span class="op">)</span>;</span>
<span id="cb12-42"><a href="#cb12-42" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A01, B10, C00<span class="op">)</span>;</span>
<span id="cb12-43"><a href="#cb12-43" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A10, B00, C10<span class="op">)</span>;</span>
<span id="cb12-44"><a href="#cb12-44" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A11, B10, C10<span class="op">)</span>;</span>
<span id="cb12-45"><a href="#cb12-45" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A00, B01, C01<span class="op">)</span>;</span>
<span id="cb12-46"><a href="#cb12-46" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A01, B11, C01<span class="op">)</span>;</span>
<span id="cb12-47"><a href="#cb12-47" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A10, B01, C11<span class="op">)</span>;</span>
<span id="cb12-48"><a href="#cb12-48" aria-hidden="true" tabindex="-1"></a>    recursive_matrix_product<span class="op">(</span>A11, B11, C11<span class="op">)</span>;</span>
<span id="cb12-49"><a href="#cb12-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-50"><a href="#cb12-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb12-51"><a href="#cb12-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-52"><a href="#cb12-52" aria-hidden="true" tabindex="-1"></a><span class="co">// Slow generic implementation</span></span>
<span id="cb12-53"><a href="#cb12-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="cb12-54"><a href="#cb12-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="cb12-55"><a href="#cb12-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="cb12-56"><a href="#cb12-56" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb12-57"><a href="#cb12-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="cb12-58"><a href="#cb12-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="cb12-59"><a href="#cb12-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="cb12-60"><a href="#cb12-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="cb12-61"><a href="#cb12-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="cb12-62"><a href="#cb12-62" aria-hidden="true" tabindex="-1"></a>      <span class="op">}</span></span>
<span id="cb12-63"><a href="#cb12-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="cb12-64"><a href="#cb12-64" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb12-65"><a href="#cb12-65" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb12-66"><a href="#cb12-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="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="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="cb13-2"><a href="#cb13-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="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  cblas_sgemm<span class="op">(</span>CblasColMajor, CblasNoTrans, CblasNoTrans,</span>
<span id="cb13-5"><a href="#cb13-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="cb13-6"><a href="#cb13-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="cb13-7"><a href="#cb13-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="cb13-8"><a href="#cb13-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,
<code>submdspan</code> as currently specified in the C++ Working Draft
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="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="dt">size_t</span> p<span class="op">&gt;</span></span>
<span id="cb14-2"><a href="#cb14-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="cb14-3"><a href="#cb14-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="cb14-4"><a href="#cb14-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="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a><span class="op">{</span> <span class="co">// same code as above</span></span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>  cblas_sgemm<span class="op">(</span>CblasColMajor, CblasNoTrans, CblasNoTrans,</span>
<span id="cb14-7"><a href="#cb14-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="cb14-8"><a href="#cb14-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="cb14-9"><a href="#cb14-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="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>This optimization and simplification would also apply to
implementations of P1673 that use a C or Fortran BLAS library where
permitted by the <code>mdspan</code> layout(s) and accessor(s).</p>
<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 (proposed
in our separate proposal <a href="https://wg21.link/p2897">P2897</a>,
which is currently in LEWG review as of the time of publication) uses
the C++ Standard Library function <code>assume_aligned</code> to
decorate pointer access.</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="dt">size_t</span> byte_alignment<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> aligned_accessor <span class="op">{</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb15-6"><a href="#cb15-6" 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="cb15-7"><a href="#cb15-7" 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="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-9"><a href="#cb15-9" 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="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType, <span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span></span>
<span id="cb15-13"><a href="#cb15-13" 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="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a>    other_byte_alignment <span class="op">==</span> byte_alignment<span class="op">)</span></span>
<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb15-16"><a href="#cb15-16" 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="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">{}</span></span>
<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference</span>
<span id="cb15-20"><a href="#cb15-20" 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="cb15-21"><a href="#cb15-21" 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="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb15-24"><a href="#cb15-24" 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="cb15-25"><a href="#cb15-25" 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="cb15-26"><a href="#cb15-26" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> p <span class="op">+</span> i;</span>
<span id="cb15-27"><a href="#cb15-27" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb15-28"><a href="#cb15-28" 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="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">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType<span class="op">&gt;</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb16-3"><a href="#cb16-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="cb16-4"><a href="#cb16-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="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-8"><a href="#cb16-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="cb16-9"><a href="#cb16-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation_t <span class="op">=</span></span>
<span id="cb16-10"><a href="#cb16-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="cb16-11"><a href="#cb16-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-12"><a href="#cb16-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="cb16-13"><a href="#cb16-13" aria-hidden="true" tabindex="-1"></a>allocation_t<span class="op">&lt;</span>ElementType<span class="op">&gt;</span></span>
<span id="cb16-14"><a href="#cb16-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="cb16-15"><a href="#cb16-15" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb16-16"><a href="#cb16-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="cb16-17"><a href="#cb16-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="cb16-18"><a href="#cb16-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="cb16-19"><a href="#cb16-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="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="kw">constexpr</span> <span class="dt">size_t</span> element_alignment <span class="op">=</span> <span class="dv">8</span>;</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">size_t</span> byte_alignment <span class="op">=</span> 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="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-4"><a href="#cb17-4" 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="cb17-5"><a href="#cb17-5" 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="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> allocation <span class="op">=</span></span>
<span id="cb17-7"><a href="#cb17-7" 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="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-9"><a href="#cb17-9" 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="cb17-10"><a href="#cb17-10" 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="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a><span class="co">// m_sub has the same layout as m,</span></span>
<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a><span class="co">// and each column of m_sub has the same overalignment.</span></span>
<span id="cb17-14"><a href="#cb17-14" 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="design-alternatives"><span class="header-section-number">3.5</span> Design alternatives<a href="#design-alternatives" class="self-link"></a></h2>
<h3 data-number="3.5.1" id="strided-layout-with-compile-time-strides"><span class="header-section-number">3.5.1</span> Strided layout with
compile-time strides<a href="#strided-layout-with-compile-time-strides" class="self-link"></a></h3>
<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
<code>aligned_accessor</code>
(<a href="https://wg21.link/p2897">P2897</a>). 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 <em>some</em> 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>
<h3 data-number="3.5.2" id="lewg-r2-polls-discussion"><span class="header-section-number">3.5.2</span> LEWG R2 polls discussion<a href="#lewg-r2-polls-discussion" class="self-link"></a></h3>
<p>LEWG’s 2023 took two polls in its review of Revision 2 of this
proposal on 2023/03/28. Both polls resulted in the status quo design,
but LEWG asked us to add to the next revision a discussion of the
questions they posed. We do so in the following sections.</p>
<h3 data-number="3.5.3" id="nest-the-new-policies-in-corresponding-existing-ones"><span class="header-section-number">3.5.3</span> Nest the new policies in
corresponding existing ones<a href="#nest-the-new-policies-in-corresponding-existing-ones" class="self-link"></a></h3>
<p>LEWG polled on the following question, with no votes in favor and
thus no consensus for change. All coauthors present voted against.</p>
<blockquote>
<p>The proposed tagged type (<code>layout_left_padded</code>) should be
a nested type (<code>layout_left::padded</code>).</p>
</blockquote>
<p>The following will explain the context and why the authors oppose
this change.</p>
<p>The suggestion was that we should change
<code>layout_left_padded&lt;padding_stride&gt;</code> and
<code>layout_right_padded&lt;padding_stride&gt;</code> from separate
layout policies (the status quo) to nested types
<code>layout_left::padded&lt;padding_stride&gt;</code> resp.
<code>layout_right::padded&lt;padding_stride&gt;</code>.</p>
<p>The issue with this change is that it is “morphologically confused,”
to borrow the words of one LEWG reviewer. The layout mapping policy
requirements <em>[mdspan.layout.policy.reqmts]</em> specify a shape
(morphology) of two levels of types. The outer type <code>MP</code> is
the layout mapping policy, which represents a family of layout mappings
parameterized by <code>extents</code> type <code>E</code>. The inner
type is the layout mapping <code>MP::mapping&lt;E&gt;</code>. Nesting a
policy inside another policy, as in <code>layout_left::padded</code>,
would break this rule that “the policy is on the outside, and the
mapping is on the inside.”</p>
<p>Note also that the <code>padding_stride</code> template parameter
must live outside the mapping. Otherwise, it wouldn’t be possible to
construct the mapping from just an <code>extents</code> object.</p>
<h3 data-number="3.5.4" id="layout-mapping-conversion-customization-point"><span class="header-section-number">3.5.4</span> Layout mapping conversion
customization point<a href="#layout-mapping-conversion-customization-point" class="self-link"></a></h3>
<p>LEWG polled on the following question, with no votes in favor and
thus no consensus for change. One coauthor voted neutral and two
coauthors voted weakly against.</p>
<blockquote>
<p>An <code>assume_layout</code> customization point should be provided
for layout conversions.</p>
</blockquote>
<p>The following will explain the context and why the authors oppose
this change.</p>
<p>The status quo design includes converting constructors between some
mappings, e.g., from <code>layout_left_padded::mapping&lt;E1&gt;</code>
to <code>layout_left::mapping&lt;E2&gt;</code>. These constructors are
conditionally <code>explicit</code> if there are nontrivial
preconditions. This design matches the existing mdspan mapping
conversions, e.g., from <code>layout_stride::mapping&lt;E1&gt;</code> to
<code>layout_left::mapping&lt;E2&gt;</code>. The intent is that implicit
conversions express and permit “type erasure,” that is, going from
information expressed in a compile-time type to information expressed in
a member variable or some other way. Type erasure here includes three
kinds of conversions.</p>
<ol type="1">
<li><p>From a more restrictive mapping to a less restrictive mapping
(e.g., from <code>layout_left::mapping&lt;E&gt;</code> to
<code>layout_stride::mapping&lt;E&gt;</code>)</p></li>
<li><p>From a mapping with static extents to a mapping with dynamic
extents (e.g., from
<code>layout_left::mapping&lt;extents&lt;int, 2, 3&gt;&gt;</code> to
<code>layout_left::mapping&lt;extents&lt;int, dynamic_extent, 3&gt;&gt;</code>)</p></li>
<li><p>Both (changing the mapping and the extents)</p></li>
</ol>
<p>Conversion in the opposite direction of type erasure generally
imposes nontrivial preconditions, so it is explicit. We permit explicit
conversions because they let users potentially improve performance by
expressing their assumptions in the type system. If users didn’t have
explicit conversions, they would likely end up reimplementing them in a
possibly less safe way.</p>
<p>LEWG reflector discussion suggested a more general approach to
conversions. Instead of conditionally explicit constructors, conversions
with nontrivial preconditions (e.g., from <code>layout_stride</code> to
<code>layout_left_padded</code> to <code>layout_left</code>) would use
an <code>assume_layout</code> customization point. This would have the
following advantages.</p>
<ol type="1">
<li><p>Users could implement conversion from their custom layout mapping
to a Standard layout mapping.</p></li>
<li><p>Adding a new layout to the Standard would not require adding
converting constructors to all the existing mappings.</p></li>
</ol>
<p>However, introducing a customization point would complicate the
design. The benefit of this complication would be low, since most custom
or new layout mappings likely could not be converted to existing layout
mappings. For example, tiled layouts or space-filling (Hilbert) curve
layouts are not strided in general, so they could not be converted to
anything in the current Standard or this proposal. In the words of one
LEWG reviewer, most layouts are “on [their] own little planet.” LEWG
discussion expressed a strong preference for not overengineering the
design by offering a conversion customization point when most
conversions don’t make sense.</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>The <code>stable</code> (main) branch of the
<a href="https://github.com/kokkos/mdspan/">reference mdspan
implementation</a> implements all of this proposal except
<code>submdspan</code> support.</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.</p>
</blockquote>
<blockquote>
<p>Make the following changes to the latest C++ Working Draft, which at
the time of writing is
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4964.pdf">N4964</a>.
All wording is relative to the latest C++ Working Draft.</p>
</blockquote>
<blockquote>
<p>In <em>[version.syn]</em>, increase the value of the
<code>__cpp_lib_submdspan</code> macro by replacing YYYMML below with
the integer literal encoding the appropriate year (YYYY) and month
(MM).</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="pp">#define __cpp_lib_submdspan </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="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> PaddingValue <span class="op">=</span> dynamic_extent<span class="op">&gt;</span> </span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_left_padded;</span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> PaddingValue <span class="op">=</span> dynamic_extent<span class="op">&gt;</span> </span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_right_padded;</span></code></pre></div>
<blockquote>
<p>In <em>[mdspan.layout.policy.overview]</em>, add the following to the
code block after the <code>layout_stride</code> definition:</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> PaddingValue<span class="op">&gt;</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_left_padded <span class="op">{</span></span>
<span id="cb20-3"><a href="#cb20-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="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> mapping;</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> PaddingValue<span class="op">&gt;</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> layout_right_padded <span class="op">{</span></span>
<span id="cb20-8"><a href="#cb20-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="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> mapping;</span>
<span id="cb20-10"><a href="#cb20-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="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="kw">class</span> LayoutLeftPaddedMapping<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><span class="kw">typename</span> LayoutLeftPaddedMapping<span class="op">::</span>extents_type, 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> LayoutLeftPaddedMapping<span class="op">&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="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="kw">class</span> LayoutLeftPaddedMapping<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><span class="kw">typename</span> LayoutLeftPaddedMapping<span class="op">::</span>extents_type, 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> LayoutLeftPaddedMapping<span class="op">&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></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<em><code>is-layout-left-padded-mapping-of</code></em><code>&lt;LayoutLeftPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutLeftPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<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>LayoutLeftPaddedMapping::extents_type::static_extent(0)</code>
does not equal <code>dynamic_extent</code>, and</p></li>
<li><p><code>LayoutLeftPaddedMapping::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>LayoutLeftPaddedMapping::padding_stride</code>.</p>
<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>extents_type::rank() &gt; 1</code> is <code>true</code>, then
<code>other.stride(1)</code> equals
<code>other.extents(0)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.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">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="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> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-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><span class="kw">typename</span> LayoutRightPaddedMapping<span class="op">::</span>extents_type, extents_type<span class="op">&gt;)</span></span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&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="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> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-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><span class="kw">typename</span> LayoutRightPaddedMapping<span class="op">::</span>extents_type, extents_type<span class="op">&gt;)</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&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></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<em><code>is-layout-right-padded-mapping-of</code></em><code>&lt;LayoutRightPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutRightPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<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>LayoutRightPaddedMapping::extents_type::static_extent(Extents::rank() - 1)</code>
does not equal <code>dynamic_extent</code>, and</p></li>
<li><p><code>LayoutRightPaddedMapping::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>LayoutRightPaddedMapping::padding_stride</code>.</p>
<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>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><span class="marginalizedparent"><a class="marginalized">(11.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">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="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-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="cb25-2"><a href="#cb25-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="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a>  false_type <span class="op">{}</span>;</span>
<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-5"><a href="#cb25-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="cb25-6"><a href="#cb25-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="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a>  true_type <span class="op">{}</span>;</span>
<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb25-9"><a href="#cb25-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="cb25-10"><a href="#cb25-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="cb25-11"><a href="#cb25-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="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="kw">class</span> Layout<span class="op">&gt;</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-right-padded</em> <span class="op">:</span> <span class="co">// exposition only</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>  false_type <span class="op">{}</span>;</span>
<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-5"><a href="#cb26-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="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> <em>is-layout-right-padded</em><span class="op">&lt;</span>layout_right_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="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>  true_type <span class="op">{}</span>;</span>
<span id="cb26-8"><a href="#cb26-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb26-9"><a href="#cb26-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="cb26-10"><a href="#cb26-10" aria-hidden="true" tabindex="-1"></a><span class="kw">constexpr</span> <span class="dt">bool</span> <em>is-layout-right-padded-mapping-of</em> <span class="co">// exposition only</span></span>
<span id="cb26-11"><a href="#cb26-11" aria-hidden="true" tabindex="-1"></a>  <em>is-layout-right-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="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-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="cb27-2"><a href="#cb27-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.leftpadded"><span class="header-section-number">4.1</span> Class template
<code>layout_left_padded::mapping</code> [mdspan.layout.leftpadded]<a href="#class-template-layout_left_paddedmapping-mdspan.layout.leftpadded" class="self-link"></a></h2>
<h3 data-number="4.1.1" id="overview-mdspan.layout.leftpadded.overview"><span class="header-section-number">4.1.1</span> Overview
[mdspan.layout.leftpadded.overview]<a href="#overview-mdspan.layout.leftpadded.overview" class="self-link"></a></h3>
<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>.</p>
<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">template</span><span class="op">&lt;</span><span class="dt">size_t</span> PaddingValue<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-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="cb28-3"><a href="#cb28-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_left_padded<span class="op">&lt;</span>PaddingValue<span class="op">&gt;::</span>mapping <span class="op">{</span></span>
<span id="cb28-4"><a href="#cb28-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb28-5"><a href="#cb28-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> padding_value <span class="op">=</span> PaddingValue;</span>
<span id="cb28-6"><a href="#cb28-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-7"><a href="#cb28-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb28-8"><a href="#cb28-8" 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="cb28-9"><a href="#cb28-9" 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="cb28-10"><a href="#cb28-10" 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="cb28-11"><a href="#cb28-11" 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>PaddingValue<span class="op">&gt;</span>;</span>
<span id="cb28-12"><a href="#cb28-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-13"><a href="#cb28-13" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb28-14"><a href="#cb28-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>static-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb28-15"><a href="#cb28-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-16"><a href="#cb28-16" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb28-17"><a href="#cb28-17" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.layout.leftpadded.cons], constructors</span></span>
<span id="cb28-18"><a href="#cb28-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb28-19"><a href="#cb28-19" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>static-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="cb28-20"><a href="#cb28-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span></span>
<span id="cb28-21"><a href="#cb28-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>static-padding-stride</em> <span class="op">==</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-22"><a href="#cb28-22" aria-hidden="true" tabindex="-1"></a>      <span class="op">:</span> mapping<span class="op">(</span>extents_type<span class="op">{})</span> <span class="op">{}</span></span>
<span id="cb28-23"><a href="#cb28-23" 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="cb28-24"><a href="#cb28-24" 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="cb28-25"><a href="#cb28-25" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherIndexType<span class="op">&gt;</span></span>
<span id="cb28-26"><a href="#cb28-26" 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, OtherIndexType padding_value<span class="op">)</span>;</span>
<span id="cb28-27"><a href="#cb28-27" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-28"><a href="#cb28-28" 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="cb28-29"><a href="#cb28-29" 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="cb28-30"><a href="#cb28-30" 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="cb28-31"><a href="#cb28-31" 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="cb28-32"><a href="#cb28-32" 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="cb28-33"><a href="#cb28-33" 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="cb28-34"><a href="#cb28-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutLeftPaddedMapping<span class="op">&gt;</span></span>
<span id="cb28-35"><a href="#cb28-35" 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="cb28-36"><a href="#cb28-36" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> LayoutLeftPaddedMapping<span class="op">&amp;)</span>;</span>
<span id="cb28-37"><a href="#cb28-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb28-38"><a href="#cb28-38" 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="cb28-39"><a href="#cb28-39" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-40"><a href="#cb28-40" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-41"><a href="#cb28-41" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> 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="cb28-42"><a href="#cb28-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-43"><a href="#cb28-43" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.layout.leftpadded.obs], observers</span></span>
<span id="cb28-44"><a href="#cb28-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">const</span> extents_type<span class="op">&amp;</span> extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <em>extents_</em>; <span class="op">}</span></span>
<span id="cb28-45"><a href="#cb28-45" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span> strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-46"><a href="#cb28-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-47"><a href="#cb28-47" 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="cb28-48"><a href="#cb28-48" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-49"><a href="#cb28-49" 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="cb28-50"><a href="#cb28-50" 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="cb28-51"><a href="#cb28-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-52"><a href="#cb28-52" 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="cb28-53"><a href="#cb28-53" 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="cb28-54"><a href="#cb28-54" 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="cb28-55"><a href="#cb28-55" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-56"><a href="#cb28-56" 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="cb28-57"><a href="#cb28-57" 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="cb28-58"><a href="#cb28-58" 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="cb28-59"><a href="#cb28-59" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-60"><a href="#cb28-60" 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="cb28-61"><a href="#cb28-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-62"><a href="#cb28-62" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutLeftPaddedMapping<span class="op">&gt;</span></span>
<span id="cb28-63"><a href="#cb28-63" 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="cb28-64"><a href="#cb28-64" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span>,</span>
<span id="cb28-65"><a href="#cb28-65" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> LayoutLeftPaddedMapping<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb28-66"><a href="#cb28-66" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-67"><a href="#cb28-67" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb28-68"><a href="#cb28-68" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">&lt;</span>index_type, <em>static-padding-stride</em><span class="op">&gt;</span> <em>stride-1</em><span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb28-69"><a href="#cb28-69" aria-hidden="true" tabindex="-1"></a>  extents_type <em>extents_</em><span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb28-70"><a href="#cb28-70" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-71"><a href="#cb28-71" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan.mapping], submdspan mapping specialization</span></span>
<span id="cb28-72"><a href="#cb28-72" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb28-73"><a href="#cb28-73" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan<span class="op">-</span>mapping<span class="op">-</span>impl<span class="op">(</span>                    <span class="co">// exposition only</span></span>
<span id="cb28-74"><a href="#cb28-74" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> see below;</span>
<span id="cb28-75"><a href="#cb28-75" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb28-76"><a href="#cb28-76" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb28-77"><a href="#cb28-77" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb28-78"><a href="#cb28-78" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span> src, SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span> <span class="op">{</span></span>
<span id="cb28-79"><a href="#cb28-79" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> src<span class="op">.</span>submdspan<span class="op">-</span>mapping<span class="op">-</span>impl<span class="op">(</span>slices<span class="op">...)</span>;</span>
<span id="cb28-80"><a href="#cb28-80" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb28-81"><a href="#cb28-81" 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 [mdspan.layout.leftpadded], let <code>P_rank</code> be the
following size <code>extents_type::rank()</code> parameter pack of
<code>size_t</code> values:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> the
empty parameter pack, if <code>extents_type::rank()</code> equals zero;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>size_t(0)</code>, if <code>extents_type::rank()</code> equals one;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> the
parameter pack <code>size_t(0)</code>, <code>size_t(1)</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_value</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_value</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="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">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>static-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>
The value is</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>0</code>, if <code>extents_type::rank()</code> equals zero or one;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> the
<code>size_t</code> value which is the least multiple of
<code>padding_value</code> that is greater than or equal to
<code>extents_type::static_extent(0)</code>, if
<code>padding_value</code> does not equal <code>dynamic_extent</code>
and <code>extents_type::static_extent(0)</code> does not equal
<code>dynamic_extent</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
<code>dynamic_extent</code>.</p></li>
</ul>
<h3 data-number="4.1.2" id="constructors-mdspan.layout.leftpadded.cons"><span class="header-section-number">4.1.2</span> Constructors
[mdspan.layout.leftpadded.cons]<a href="#constructors-mdspan.layout.leftpadded.cons" class="self-link"></a></h3>
<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>static-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">1</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">2</a></span>
<em>Preconditions:</em> If <code>extents_type::rank()</code> is greater
than one and <code>padding_value</code> does not equal
<code>dynamic_extent</code>, then the least multiple of
<code>padding_stride</code> greater than or 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">3</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>ext</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> if
<em><code>static-padding-stride</code></em> is not equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-1</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> OtherIndexType<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, OtherIndexType pad<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>is_convertible_v&lt;OtherIndexType, index_type&gt;</code> is
<code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<code>is_nothrow_constructible_v&lt;index_type, OtherIndexType&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>pad</code> is representable as a value of type
<code>index_type</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>extents_type::</code><em><code>index-cast</code></em><code>(pad)</code>
is greater than zero,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span> if
<code>extents_type::rank()</code> is greater than one, then the least
multiple of <code>pad</code> greater than or equal to
<code>ext.extent(0)</code> is representable as a value of type
<code>index_type</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.4)</a></span> if
<code>padding_value</code> is not equal to <code>dynamic_extent</code>,
<code>padding_value</code> equals
<code>extents_type::</code><em><code>index-cast</code></em><code>(pad)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>ext</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span> if
<em><code>static-padding-stride</code></em> is equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-1</code></em> with the least multiple of
<code>pad</code> greater than or equal to
<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">7</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">8</a></span>
<em>Mandates:</em> If <code>OtherExtents::rank() &gt; 1</code>,
<em><code>static-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>static-padding-stride</code></em> equals
<code>OtherExtents::static_extent(0)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_value == dynamic_extent</code> is <code>false</code>, then
<code>other.stride(1)</code> equals the least multiple of
<code>padding_value</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">(9.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">10</a></span>
<em>Effects:</em> Equivalent to
<code>mapping(other.extents())</code>;</p>
<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">11</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">12</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_value == dynamic_extent</code> is <code>false</code>, then
<code>other.stride(1)</code> equals the least multiple of
<code>padding_value</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(0))</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.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">(12.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">(12.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">13</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>other.extents()</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.2)</a></span> is
<code>static-padding-stride</code> is equal to
<code>dynamic_extent</code> direct-non-list-initializes
<em><code>stride-1</code></em> with
<code>other.stride(1)</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="kw">class</span> LayoutLeftPaddedMapping<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> LayoutLeftPaddedMapping<span class="op">&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(14.1)</a></span>
<em><code>is-layout-left-padded-mapping-of</code></em><code>&lt;LayoutLeftPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(14.2)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutLeftPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Mandates:</em>
<code>padding_value == dynamic_extent || LayoutLeftPaddedMapping::padding_value == dynamic_extent || padding_value == LayoutLeftPaddedMapping::padding_value</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.1)</a></span> If
<code>extents_type::rank() &gt; 1</code> is <code>true</code> and
<code>padding_value</code> does not equal <code>dynamic_extent</code>,
then <code>other.stride(1)</code> equals the least multiple of
<code>padding_value</code> greater than or equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extent(0))</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.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">17</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(17.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>other.extents()</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(17.2)</a></span> if
<code>static-padding-stride</code> is equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-1</code></em> with
<code>other.stride(1)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">18</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent to:
<code>extents_type::rank() &gt; 1 &amp;&amp; (padding_value != dynamic_extent || LayoutLeftPaddedMapping::padding_value == 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="kw">class</span> LayoutRightPaddedMapping<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> <span class="co">/* see below */</span> <span class="op">)</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> LayoutRightPaddedMapping<span class="op">&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.1)</a></span>
<em><code>is-layout-right-padded-mapping-of</code></em><code>&lt;LayoutRightPaddedMapping&gt;</code>
is <code>true</code> or
<em><code>is-mapping-of</code></em><code>&lt;layout_right, LayoutRightPaddedMapping&gt;</code>
is `true,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.2)</a></span>
<code>extents_type::rank()</code> equals zero or one, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.3)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutRightPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">20</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">21</a></span>
<em>Effects:</em> direct-non-list-initializes
<em><code>extents_</code></em> with <code>other.extents()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent to:
<code>! is_convertible_v&lt;typename LayoutRightPaddedMapping::extents_type, extents_type&gt;</code>.</p>
<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>
<h3 data-number="4.1.3" id="observers-mdspan.layout.leftpadded.obs"><span class="header-section-number">4.1.3</span> Observers
[mdspan.layout.leftpadded.obs]<a href="#observers-mdspan.layout.leftpadded.obs" class="self-link"></a></h3>
<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> array<span class="op">&lt;</span>index_type, extents_type<span class="op">::</span>rank<span class="op">()&gt;</span></span>
<span id="cb37-2"><a href="#cb37-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">1</a></span>
<em>Returns:</em>
<code>array&lt;index_type, extents_type::rank()&gt;({stride(P_rank)...})</code>.</p>
<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> 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">2</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>0</code> if the multidimensional index space
<em><code>extents_</code></em> is empty, otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>*this(((extents_(P_rank) - index_type(1))...)) + 1</code></p></li>
</ul>
<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">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="cb39-2"><a href="#cb39-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">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>sizeof...(Indices) == Extents::rank()</code> is
<code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<code>(is_convertible_v&lt;Indices, index_type&gt; &amp;&amp; ...)</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.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">4</a></span>
<em>Precondition:</em>
<code>extents_type::</code><em><code>index-cast</code></em><code>(idxs)</code>
is a multidimensional index in <code>extents()</code>
(<em>[mdspan.overview]</em>).</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Returns:</em>
<code>((static_cast&lt;index_type&gt;(idxs) * stride(P_rank)) + ... + 0);</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">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">6</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.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">(6.2)</a></span>
else, if <em><code>static-padding-stride</code></em> nor
<code>extents_type::static_extent(0)</code> equal
<code>dynamic_extent</code>, then
<em><code>static-padding-stride</code></em><code>== extents_type::static_extent(0)</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.3)</a></span>
otherwise, <code>false</code>.</p></li>
</ul>
<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">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">7</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span> If
<code>extents_type::rank() &lt; 2</code> is <code>true</code>, then
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
else,
<em><code>extents_</code></em><code>.extent(0) == stride(1)</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> 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">8</a></span>
<em>Preconditions:</em> <code>r</code> is smaller than
<code>extents_type::rank()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<code>1</code>, if <code>r</code> equals <code>0</code>;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<em><code>stride-1</code></em><code>.extent(0)</code>, if <code>r</code>
equals <code>1</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3)</a></span> the
product of <em><code>stride-1</code></em><code>.extent(0)</code> and all
values <em><code>extents_</code></em><code>.extent(k)</code> with
<code>k</code> in the range of <span class="math inline">[1,</span>
<code>r</code> <span class="math inline">)</span>.</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">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutLeftPaddedMapping<span class="op">&gt;</span></span>
<span id="cb43-2"><a href="#cb43-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="cb43-3"><a href="#cb43-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mapping<span class="op">&amp;</span> x,</span>
<span id="cb43-4"><a href="#cb43-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> LayoutLeftPaddedMapping<span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">noexcept</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>
<em><code>is-layout-left-padded-mapping-of</code></em><code>&lt;LayoutLeftPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.2)</a></span>
<code>typename LayoutLeftPaddedMapping::extents_type::rank() == extents_type::rank()</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Returns:</em> <code>true</code> if</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>x.extents() == y.extents()</code> is <code>true</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.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.rightpadded"><span class="header-section-number">4.2</span> Class template
<code>layout_right_padded::mapping</code> [mdspan.layout.rightpadded]<a href="#class-template-layout_right_paddedmapping-mdspan.layout.rightpadded" class="self-link"></a></h2>
<h3 data-number="4.2.1" id="overview-mdspan.layout.rightpadded.overview"><span class="header-section-number">4.2.1</span> Overview
[mdspan.layout.rightpadded.overview]<a href="#overview-mdspan.layout.rightpadded.overview" class="self-link"></a></h3>
<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(extents_type::rank()-2)</code> can be greater
than or equal to
<code>extents_type::extent(extents_type::rank()-1)</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> PaddingValue<span class="op">&gt;</span></span>
<span id="cb44-2"><a href="#cb44-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="cb44-3"><a href="#cb44-3" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> layout_right_padded<span class="op">&lt;</span>PaddingValue<span class="op">&gt;::</span>mapping <span class="op">{</span></span>
<span id="cb44-4"><a href="#cb44-4" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb44-5"><a href="#cb44-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> padding_value <span class="op">=</span> PaddingValue;</span>
<span id="cb44-6"><a href="#cb44-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-7"><a href="#cb44-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> extents_type <span class="op">=</span> Extents;</span>
<span id="cb44-8"><a href="#cb44-8" 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="cb44-9"><a href="#cb44-9" 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="cb44-10"><a href="#cb44-10" 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="cb44-11"><a href="#cb44-11" 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>PaddingValue<span class="op">&gt;</span>;</span>
<span id="cb44-12"><a href="#cb44-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-13"><a href="#cb44-13" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb44-14"><a href="#cb44-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>rank_</em> <span class="op">=</span> extents_type<span class="op">::</span>rank<span class="op">()</span>; <span class="co">// exposition only</span></span>
<span id="cb44-15"><a href="#cb44-15" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>static-padding-stride</em> <span class="op">=</span> <span class="co">/* see-below */</span>; <span class="co">// exposition only</span></span>
<span id="cb44-16"><a href="#cb44-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>last-static-extent</em> <span class="op">=</span> <span class="co">// exposition only</span></span>
<span id="cb44-17"><a href="#cb44-17" aria-hidden="true" tabindex="-1"></a>    extents_type<span class="op">::</span>static_extent<span class="op">(</span><em>rank_</em> <span class="op">-</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb44-18"><a href="#cb44-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-19"><a href="#cb44-19" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb44-20"><a href="#cb44-20" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.layout.rightpadded.cons], constructors</span></span>
<span id="cb44-21"><a href="#cb44-21" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb44-22"><a href="#cb44-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>static-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="cb44-23"><a href="#cb44-23" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> mapping<span class="op">()</span></span>
<span id="cb44-24"><a href="#cb44-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span><span class="op">(</span><em>static-padding-stride</em> <span class="op">==</span> dynamic_extent<span class="op">)</span> <span class="kw">noexcept</span>;</span>
<span id="cb44-25"><a href="#cb44-25" aria-hidden="true" tabindex="-1"></a>      <span class="op">:</span> mapping<span class="op">(</span>extents_type<span class="op">{})</span> <span class="op">{}</span></span>
<span id="cb44-26"><a href="#cb44-26" 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="cb44-27"><a href="#cb44-27" 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="cb44-28"><a href="#cb44-28" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherIndexType<span class="op">&gt;</span></span>
<span id="cb44-29"><a href="#cb44-29" 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, OtherIndexType padding_value<span class="op">)</span>;</span>
<span id="cb44-30"><a href="#cb44-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-31"><a href="#cb44-31" 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="cb44-32"><a href="#cb44-32" 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="cb44-33"><a href="#cb44-33" 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="cb44-34"><a href="#cb44-34" 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="cb44-35"><a href="#cb44-35" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>rank_</em> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb44-36"><a href="#cb44-36" 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="cb44-37"><a href="#cb44-37" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb44-38"><a href="#cb44-38" 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="cb44-39"><a href="#cb44-39" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&amp;)</span>;</span>
<span id="cb44-40"><a href="#cb44-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutLeftPaddedMapping<span class="op">&gt;</span></span>
<span id="cb44-41"><a href="#cb44-41" 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="cb44-42"><a href="#cb44-42" aria-hidden="true" tabindex="-1"></a>      mapping<span class="op">(</span><span class="kw">const</span> LayoutLeftPaddedMapping<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb44-43"><a href="#cb44-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-44"><a href="#cb44-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> 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="cb44-45"><a href="#cb44-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-46"><a href="#cb44-46" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.layout.rightpadded.obs], observers</span></span>
<span id="cb44-47"><a href="#cb44-47" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">const</span> extents_type<span class="op">&amp;</span> extents<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span> <span class="op">{</span> <span class="cf">return</span> <em>extents_</em>; <span class="op">}</span></span>
<span id="cb44-48"><a href="#cb44-48" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> array<span class="op">&lt;</span>index_type, <em>rank_</em><span class="op">&gt;</span> strides<span class="op">()</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span>
<span id="cb44-49"><a href="#cb44-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-50"><a href="#cb44-50" 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="cb44-51"><a href="#cb44-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-52"><a href="#cb44-52" 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="cb44-53"><a href="#cb44-53" 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="cb44-54"><a href="#cb44-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-55"><a href="#cb44-55" 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="cb44-56"><a href="#cb44-56" 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="cb44-57"><a href="#cb44-57" 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="cb44-58"><a href="#cb44-58" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-59"><a href="#cb44-59" 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="cb44-60"><a href="#cb44-60" 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="cb44-61"><a href="#cb44-61" 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="cb44-62"><a href="#cb44-62" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-63"><a href="#cb44-63" 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="cb44-64"><a href="#cb44-64" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-65"><a href="#cb44-65" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb44-66"><a href="#cb44-66" 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-67"><a href="#cb44-67" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span>,</span>
<span id="cb44-68"><a href="#cb44-68" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&amp;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb44-69"><a href="#cb44-69" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-70"><a href="#cb44-70" aria-hidden="true" tabindex="-1"></a><span class="kw">private</span><span class="op">:</span></span>
<span id="cb44-71"><a href="#cb44-71" aria-hidden="true" tabindex="-1"></a>  extents<span class="op">&lt;</span>index_type, <em>static-padding-stride</em><span class="op">&gt;</span> <em>stride-rm2</em><span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb44-72"><a href="#cb44-72" aria-hidden="true" tabindex="-1"></a>  extents_type <em>extents_</em><span class="op">{}</span>; <span class="co">// exposition only</span></span>
<span id="cb44-73"><a href="#cb44-73" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-74"><a href="#cb44-74" aria-hidden="true" tabindex="-1"></a>  <span class="co">// [mdspan.submdspan.mapping], submdspan mapping specialization</span></span>
<span id="cb44-75"><a href="#cb44-75" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb44-76"><a href="#cb44-76" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan<span class="op">-</span>mapping<span class="op">-</span>impl<span class="op">(</span>                    <span class="co">// exposition only</span></span>
<span id="cb44-77"><a href="#cb44-77" aria-hidden="true" tabindex="-1"></a>      SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> see below;</span>
<span id="cb44-78"><a href="#cb44-78" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb44-79"><a href="#cb44-79" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb44-80"><a href="#cb44-80" aria-hidden="true" tabindex="-1"></a>    <span class="kw">friend</span> <span class="kw">constexpr</span> <span class="kw">auto</span> submdspan_mapping<span class="op">(</span></span>
<span id="cb44-81"><a href="#cb44-81" aria-hidden="true" tabindex="-1"></a>      <span class="kw">const</span> mapping<span class="op">&amp;</span> src, SliceSpecifiers<span class="op">...</span> slices<span class="op">)</span> <span class="op">{</span></span>
<span id="cb44-82"><a href="#cb44-82" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> src<span class="op">.</span>submdspan<span class="op">-</span>mapping<span class="op">-</span>impl<span class="op">(</span>slices<span class="op">...)</span>;</span>
<span id="cb44-83"><a href="#cb44-83" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb44-84"><a href="#cb44-84" 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 [mdspan.layout.rightpadded], let <code>P_rank</code> be the
following size <em><code>rank_</code></em> parameter pack of
<code>size_t</code> values:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span> the
empty parameter pack, if <em><code>rank_</code></em> equals zero;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>size_t(0)</code>, if <em><code>rank_</code></em> equals one;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.3)</a></span> the
parameter pack <code>size_t(0)</code>, <code>size_t(1)</code>, …,
<em><code>rank_</code></em> <code>- 1</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> If</p>
<ul>
<li><p><em><code>rank_</code></em> is greater than one,</p></li>
<li><p><code>padding_value</code> does not equal
<code>dynamic_extent</code>, and</p></li>
<li><p><em><code>last-static-extent</code></em> does not equal
<code>dynamic_extent</code>,</p></li>
</ul>
<p>then the least multiple of <code>padding_value</code> that is greater
than or equal to <em><code>last-static-extent</code></em> 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="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">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> <em>static-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>
The value is</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>0</code>, if <em><code>rank_</code></em> equals zero or one;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span> the
<code>size_t</code> value which is the least multiple of
<code>padding_value</code> that is greater than or equal to
<em><code>last-static-extent</code></em>, if <code>padding_value</code>
does not equal <code>dynamic_extent</code> and
<em><code>last-static-extent</code></em> does not equal
<code>dynamic_extent</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.3)</a></span>
<code>dynamic_extent</code>.</p></li>
</ul>
<h3 data-number="4.2.2" id="constructors-mdspan.layout.rightpadded.cons"><span class="header-section-number">4.2.2</span> Constructors
[mdspan.layout.rightpadded.cons]<a href="#constructors-mdspan.layout.rightpadded.cons" class="self-link"></a></h3>
<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">constexpr</span> mapping<span class="op">()</span> </span>
<span id="cb46-2"><a href="#cb46-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span><em>static-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">1</a></span>
<em>Effects:</em> Equivalent to
<code>mapping(extents_type{});</code>.</p>
<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">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">2</a></span>
<em>Preconditions:</em> If <em><code>rank_</code></em> is greater than
one and <code>padding_value</code> does not equal
<code>dynamic_extent</code>, then the least multiple of
<code>padding_stride</code> greater than or equal to
<code>ext.extent(</code><em><code>rank_</code></em> <code>- 1)</code> is
representable as a value of type <code>index_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>ext</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span> if
<em><code>static-padding-stride</code></em> is not equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-rm2</code></em> with
<code>ext.extent(</code><em><code>rank_</code></em>
<code>- 1)</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">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherIndexType<span class="op">&gt;</span></span>
<span id="cb48-2"><a href="#cb48-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, OtherIndexType pad<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span>
<code>is_convertible_v&lt;OtherIndexType, index_type&gt;</code> is
<code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<code>is_nothrow_constructible_v&lt;index_type, OtherIndexType&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.1)</a></span>
<code>pad</code> is representable as a value of type
<code>index_type</code>,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.2)</a></span>
<code>extents_type::</code><em><code>index-cast</code></em><code>(pad)</code>
is greater than zero,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.3)</a></span> if
<em><code>rank_</code></em> is greater than one, then the least multiple
of <code>pad</code> greater than or equal to
<code>ext.extent(</code><em><code>rank_</code></em> <code>- 1)</code> is
representable as a value of type <code>index_type</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(5.4)</a></span> if
<code>padding_value</code> is not equal to <code>dynamic_extent</code>,
<code>padding_value</code> equals
<code>extents_type::</code><em><code>index-cast</code></em><code>(pad)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>ext</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span> if
<em><code>static-padding-stride</code></em> is equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-rm2</code></em> with the least multiple of
<code>pad</code> greater than or equal to
<code>ext.extent(</code><em><code>rank_</code></em>
<code>- 1)</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">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb49-2"><a href="#cb49-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="cb49-3"><a href="#cb49-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">7</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">8</a></span>
<em>Mandates:</em> If <code>OtherExtents::rank() &gt; 1</code>,
<em><code>static-padding-stride</code></em> does not equal
<code>dynamic_extent</code>, and
<code>OtherExtents::static_extent(</code><em><code>rank_</code></em><code>- 1)</code>
does not equal <code>dynamic_extent</code>, then
<em><code>static-padding-stride</code></em> equals
<code>OtherExtents::static_extent(</code><em><code>rank_</code></em><code>- 1)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span> If
<em><code>rank_</code></em> <code>&gt; 1</code> is <code>true</code> and
<code>padding_value == dynamic_extent</code> is <code>false</code>, then
<code>other.stride(</code><em><code>rank_</code></em><code>- 2)</code>
equals the least multiple of <code>padding_value</code> greater than or
equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(</code><em><code>rank_</code></em><code>- 1))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.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">10</a></span>
<em>Effects:</em> Equivalent to
<code>mapping(other.extents())</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">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherExtents<span class="op">&gt;</span></span>
<span id="cb50-2"><a href="#cb50-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span><span class="op">(</span><em>rank_</em> <span class="op">&gt;</span> <span class="dv">0</span><span class="op">)</span></span>
<span id="cb50-3"><a href="#cb50-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">11</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">12</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.1)</a></span> If
<em><code>rank_</code></em><code>&gt; 1</code> is <code>true</code> and
<code>padding_value == dynamic_extent</code> is <code>false</code>, then
<code>other.stride(</code><em><code>rank_</code></em><code>- 2)</code>
equals the least multiple of <code>padding_value</code> greater than or
equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extents().extent(</code><em><code>rank_</code></em><code>- 1))</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.2)</a></span> If
<em><code>rank_</code></em><code>&gt; 0</code> is <code>true</code>,
then
<code>other.stride(</code><em><code>rank_</code></em><code>- 1)</code>
equals 1.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.3)</a></span> If
<em><code>rank_</code></em><code>&gt; 2</code> is <code>true</code>, and
then for all <code>r</code> in the range <span class="math inline">[</span>
<code>0,</code><em><code>rank_</code></em><code>- 2</code><span class="math inline">)</span>, <code>other.stride(r)</code> equals
<code>other.extents().</code><em><code>rev-prod-of-extents(r)</code></em><code>/ other.extents().extent(</code><em><code>rank_</code></em><code>- 1) * other.stride(</code><em><code>rank_</code></em><code>- 2)</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(12.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">13</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>other.extents()</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(13.2)</a></span> is
<code>static-padding-stride</code> is equal to
<code>dynamic_extent</code> direct-non-list-initializes
<em><code>stride-rm2</code></em> with
<code>other.stride(</code><em><code>rank_</code></em><code>- 2)</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> LayoutRightPaddedMapping<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> <span class="kw">explicit</span><span class="op">(</span> <span class="co">/* see below */</span> <span class="op">)</span></span>
<span id="cb51-3"><a href="#cb51-3" aria-hidden="true" tabindex="-1"></a>    mapping<span class="op">(</span><span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&amp;</span> other<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">14</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(14.1)</a></span>
<em><code>is-layout-right-padded-mapping-of</code></em><code>&lt;LayoutRightPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(14.2)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutRightPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">15</a></span>
<em>Mandates:</em>
<code>padding_value == dynamic_extent || LayoutRightPaddedMapping::padding_value == dynamic_extent || padding_value == LayoutRightPaddedMapping::padding_value</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">16</a></span>
<em>Preconditions:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.1)</a></span> If
<em><code>rank_</code></em><code>&gt; 1</code> is <code>true</code> and
<code>padding_value</code> does not equal <code>dynamic_extent</code>,
then
<code>other.stride(</code><em><code>rank_</code></em><code>- 2)</code>
equals the least multiple of <code>padding_value</code> greater than or
equal to
<code>extents_type::</code><em><code>index-cast</code></em><code>(other.extent(</code><em><code>rank_</code></em><code>- 1))</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(16.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">17</a></span>
<em>Effects:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(17.1)</a></span>
Direct-non-list-initializes <em><code>extents_</code></em> with
<code>other.extents()</code>, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(17.2)</a></span> if
<code>static-padding-stride</code> is equal to
<code>dynamic_extent</code>, direct-non-list-initializes
<em><code>stride-rm2</code></em> with
<code>other.stride(</code><em><code>rank_</code></em><code>- 2)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">18</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent
to:<em><code>rank_</code></em><code>&gt; 1 &amp;&amp; (padding_value != dynamic_extent || LayoutRightPaddedMapping::padding_value == dynamic_extent)</code>.</p>
<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> LayoutLeftPaddedMapping<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> <span class="co">/* see below */</span> <span class="op">)</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> LayoutLeftPaddedMapping<span class="op">&amp;</span> other<span class="op">)</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">19</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.1)</a></span>
<em><code>is-layout-left-padded-mapping-of</code></em><code>&lt;LayoutLeftPaddedMapping&gt;</code>
is <code>true</code> or
<em><code>is-mapping-of</code></em><code>&lt;layout_left, LayoutLeftPaddedMapping&gt;</code>
is `true,</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.2)</a></span>
<code>extents_type::rank()</code> equals zero or one, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(19.3)</a></span>
<code>is_constructible_v&lt;extents_type, typename LayoutLeftPaddedMapping::extents_type&gt;</code>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">20</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">21</a></span>
<em>Effects:</em> direct-non-list-initializes
<em><code>extents_</code></em> with <code>other.extents()</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">22</a></span>
<em>Remarks:</em> The expression inside <code>explicit</code> is
equivalent to:
<code>! is_convertible_v&lt;typename LayoutLeftPaddedMapping::extents_type, extents_type&gt;</code>.</p>
<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>
<h3 data-number="4.2.3" id="observers-mdspan.layout.rightpadded.obs"><span class="header-section-number">4.2.3</span> Observers
[mdspan.layout.rightpadded.obs]<a href="#observers-mdspan.layout.rightpadded.obs" class="self-link"></a></h3>
<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">constexpr</span> array<span class="op">&lt;</span>index_type, <em>rank_</em><span class="op">&gt;</span></span>
<span id="cb53-2"><a href="#cb53-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">1</a></span>
<em>Returns:</em>
<code>array&lt;index_type,</code><em><code>rank_</code></em><code>&gt;({stride(P_rank)...})</code>.</p>
<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">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">2</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.1)</a></span>
<code>0</code> if the multidimensional index space
<em><code>extents_</code></em> is empty, otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(2.2)</a></span>
<code>*this(((extents_(P_rank) - index_type(1))...)) + 1</code></p></li>
</ul>
<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="kw">class</span><span class="op">...</span> Indices<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="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">3</a></span>
<em>Constraints:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<code>sizeof...(Indices) == Extents::rank()</code> is
<code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<code>(is_convertible_v&lt;Indices, index_type&gt; &amp;&amp; ...)</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.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">4</a></span>
<em>Precondition:</em>
<code>extents_type::</code><em><code>index-cast</code></em><code>(idxs)</code>
is a multidimensional index in <code>extents()</code>
(<em>[mdspan.overview]</em>).</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Returns:</em>
<code>((static_cast&lt;index_type&gt;(idxs) * stride(P_rank)) + ... + 0);</code>.</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">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">6</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span> If
<em><code>rank_</code></em> equals zero or one, then
<code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
else, if neither <em><code>static-padding-stride</code></em> nor
<em><code>last-static-extent</code></em> equal
<code>dynamic_extent</code>, then
<em><code>static-padding-stride</code></em> equals
<em><code>last-static-extent</code></em>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.3)</a></span>
otherwise, <code>false</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> <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">7</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.1)</a></span> If
<em><code>rank_</code></em><code>&lt; 2</code> is <code>true</code>,
then <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(7.2)</a></span>
else,
<em><code>extents_</code></em><code>.extent(</code><em><code>rank_</code></em><code>- 1) == stride(</code><em><code>rank_</code></em><code>- 2)</code>.</p></li>
</ul>
<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 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">8</a></span>
<em>Preconditions:</em> <code>r</code> is smaller than
<em><code>rank_</code></em>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<code>1</code>, if <code>r</code> equals
<em><code>rank_</code></em><code>- 1</code>; otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<em><code>stride-rm2</code></em><code>.extent(0)</code>, if
<code>r</code> equals <em><code>rank_</code></em><code>- 2</code>;
otherwise</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(9.3)</a></span> the
product of <em><code>stride-rm2</code></em><code>.extent(0)</code> and
all values <em><code>extents_</code></em><code>.extent(k)</code> with
<code>k</code> in the range of <span class="math inline">[</span><code>r + 1</code>,
<em><code>rank_</code></em><code>- 1</code> <span class="math inline">)</span>.</p></li>
</ul>
<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> LayoutRightPaddedMapping<span class="op">&gt;</span></span>
<span id="cb59-2"><a href="#cb59-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="cb59-3"><a href="#cb59-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> mapping<span class="op">&amp;</span> x,</span>
<span id="cb59-4"><a href="#cb59-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> LayoutRightPaddedMapping<span class="op">&amp;</span> y<span class="op">)</span> <span class="kw">noexcept</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>
<em><code>is-layout-right-padded-mapping-of</code></em><code>&lt;LayoutRightPaddedMapping&gt;</code>
is <code>true</code>.</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(10.2)</a></span>
<code>typename LayoutRightPaddedMapping::extents_type::rank() ==</code><em><code>rank_</code></em>
is <code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">11</a></span>
<em>Returns:</em> <code>true</code> if</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.1)</a></span>
<code>x.extents() == y.extents()</code> is <code>true</code>;
and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(11.2)</a></span> if
<em><code>rank_</code></em><code>&gt; 1</code> is <code>true</code>,
then
<code>x.stride(</code><em><code>rank_</code></em><code>- 2) == y.stride(</code><em><code>rank_</code></em><code>- 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>Replace Section � [mdspan.submdspan.mapping] (“Layout specializations
of <code>submdspan_mapping</code>”), with:</p>
</blockquote>
<p><b>24.7.3.7.6 Specialization of <code>submdspan_mapping</code>
[mdspan.submdspan.mapping]</b></p>
<p><b>24.7.3.7.6.1 Common [mdspan.submdspan.mapping.common]</b></p>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
The following elements apply to all functions in
[mdspan.submdspan.mapping].</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Constraints:</em> <code>sizeof...(slices)</code> equals
<code>extents_type::rank()</code>,</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Mandates:</em> For each rank index <code>k</code> of
<code>extents()</code>, exactly one of the following is true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.1)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<code>convertible_to&lt;index_type&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.2)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.3)</a></span>
<code>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></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(3.4)</a></span>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions:</em> For each rank index <code>k</code> of
<code>extents()</code>, all of the following are true:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.1)</a></span> if
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code></p>
<ul>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.extent</code>
<span class="math inline"> = 0</span>, or</p></li>
<li><p><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &gt; 0</span>; and</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(4.2)</a></span>
<span class="math inline">0≤</span>
<em><code>first</code></em><code>_&lt;index_type, k&gt;(slices...)</code>
<span class="math inline">≤</span>
<em><code>last_&lt;k&gt;</code></em><code>(extents(), slices...)</code>
<span class="math inline">≤</span>
<code>extents.extent(k)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Let <code>sub_ext</code> be the result of
<code>submdspan_extents(extents(), slices...)</code> and let
<code>SubExtents</code> be <code>decltype(sub_ext)</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Let <code>sub_strides</code> be an
<code>array&lt;SubExtents::index_type, SubExtents::rank()&gt;</code>
such that for each rank index <code>k</code> of <code>extents()</code>
for which <em><code>map-rank</code></em><code>[k]</code> is not
<code>dynamic_extent</code>,
<code>sub_strides[</code><em><code>map-rank</code></em><code>[k]]</code>
equals:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.1)</a></span>
<code>stride(k) *</code><em><code>de-ice</code></em><code>(</code><span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride)</code>
if <span class="math inline"><em>S</em><sub><em>k</em></sub></span> is a
specialization of <code>strided_slice</code> and <span class="math inline"><em>s</em><sub><em>k</em></sub></span><code>.stride</code>
<span class="math inline"> &lt; <em>s</em><sub><em>k</em></sub></span><code>.extent</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(6.2)</a></span>
otherwise, <code>stride(k)</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
Let <code>P</code> be a parameter pack such that
<code>is_same_v&lt;make_index_sequence&lt;rank()&gt;, index_sequence&lt;P...&gt;&gt;</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
Let <code>offset</code> be a value of type <code>size_t</code> equal to
<code>(*this)(</code><em><code>first</code></em><code>_&lt;index_type, P&gt;(slices...)...)</code>.</p>
<p><b>24.7.3.7.6.2 <code>layout_left</code> specialization of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping.left]</b></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">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb60-2"><a href="#cb60-2" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb60-3"><a href="#cb60-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_left<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>    <span class="co">// <em>exposition only</em></span></span>
<span id="cb60-4"><a href="#cb60-4" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank()==0</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_left::mapping(sub_ext), offset}</code>,
if</p>
<ul>
<li><p>for each <code>k</code> in the range <span class="math inline">[0,</span> <code>SubExtents::rank()-1</code><span class="math inline">)</span>, <code>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()-1</code>,
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul>
<p><i>[Note: </i> If the above conditions are true, all <span class="math inline"><em>S</em><sub><em>k</em></sub></span> with
<code>k</code> larger than <code>SubExtents::rank()-1</code> are
convertible to <code>index_type</code>. <i>- end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_left_padded&lt;Extents::static_extent(0)&gt;::mapping(sub_ext, extent(0)), offset}</code>
if</p>
<ul>
<li><p><span class="math inline"><em>S</em><sub>0</sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</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>, <code>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()-1</code>,
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
<p><b>24.7.3.7.6.3 <code>layout_right</code> specialization of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping.right]</b></p>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb61-2"><a href="#cb61-2" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb61-3"><a href="#cb61-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_right<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>   <span class="co">// <em>exposition only</em></span></span>
<span id="cb61-4"><a href="#cb61-4" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank()==0</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_right::mapping(sub_ext), offset}</code>,
if</p>
<ul>
<li><p>for each <code>k</code> in the range <span class="math inline">[</span>
<code>Extents::rank() - SubExtents::rank()+1, Extents::rank()</code><span class="math inline">)</span>, <code>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>Extents::rank()-SubExtents::rank()</code>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul>
<p><i>[Note: </i> If the above conditions are true, all <span class="math inline"><em>S</em><sub><em>k</em></sub></span> with
<code>k</code> <span class="math inline">&lt;</span>
<code>Extents::rank()-SubExtents::rank()</code> are convertible to
<code>index_type</code>. <i>- end note]</i></p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_right_padded&lt;Extents::static_extent(Extents::rank()-1)&gt;::template mapping(sub_ext, extent(Extents::rank() - 1)), offset}</code>
if</p>
<ul>
<li><p>for <code>k</code> equal to <code>Extents::rank() - 1</code>
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</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>, <code>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>Extents::rank()-SubExtents::rank()</code>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
<p><b>24.7.3.7.6.4 <code>layout_stride</code> specialization of
<code>submdspan_mapping</code> [mdspan.submdspan.mapping.stride]</b></p>
<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">template</span><span class="op">&lt;</span><span class="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb62-2"><a href="#cb62-2" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb62-3"><a href="#cb62-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_stride<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>  <span class="co">// <em>exposition only</em></span></span>
<span id="cb62-4"><a href="#cb62-4" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank()==0</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
<p><b>24.7.3.7.6.5 <code>layout_left_padded</code> specialization of
<code>submdspan_mapping</code>
[mdspan.submdspan.mapping.leftpadded]</b></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="kw">class</span> Extents<span class="op">&gt;</span></span>
<span id="cb63-2"><a href="#cb63-2" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb63-3"><a href="#cb63-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_left_padded<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>    <span class="co">// <em>exposition only</em></span></span>
<span id="cb63-4"><a href="#cb63-4" aria-hidden="true" tabindex="-1"></a>    SliceSpecifiers <span class="op">...</span> slices<span class="op">)</span> <span class="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank()==0</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_left_padded&lt;padding_value&gt;::mapping(sub_ext), offset}</code>,
if <code>Extents::rank()==1</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_left_padded&lt;padding_value&gt;::mapping(sub_ext, stride(1)), offset}</code>
if</p>
<ul>
<li><p><span class="math inline"><em>S</em><sub>0</sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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 each <code>k</code> in the range <span class="math inline">[</span><code>1, SubExtents::rank()-1</code><span class="math inline">)</span>, <code>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()-1</code>,
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
<p><b>24.7.3.7.6.6 <code>layout_right_padded</code> specialization of
<code>submdspan_mapping</code>
[mdspan.submdspan.mapping.rightpadded]</b></p>
<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<span class="op">&gt;</span></span>
<span id="cb64-2"><a href="#cb64-2" 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> SliceSpecifiers<span class="op">&gt;</span></span>
<span id="cb64-3"><a href="#cb64-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">auto</span> layout_right_padded<span class="op">::</span>mapping<span class="op">&lt;</span>Extents<span class="op">&gt;::</span><em>submdspan-mapping-impl</em><span class="op">(</span>    <span class="co">// <em>exposition only</em></span></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="kw">const</span> <span class="op">-&gt;</span> <em>see below</em>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Returns:</em></p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>submdspan_mapping_result{*this, 0}</code>, if
<code>Extents::rank() == 0</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_right_padded&lt;padding_value&gt;::mapping(sub_ext), offset}</code>,
if <code>Extents::rank() == 1</code> is <code>true</code>;</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.3)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_right_padded&lt;padding_value&gt;::mapping(sub_ext, stride(Extents::rank() - 1)), offset}</code>
if</p>
<ul>
<li><p>for <code>k</code> equal to <code>Extents::rank() - 1</code>,
<span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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 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>, <code>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>Extents::rank()-SubExtents::rank()</code>, <span class="math inline"><em>S</em><sub><em>k</em></sub></span> models
<em><code>index-pair-like</code></em><code>&lt;index_type&gt;</code> or
<code>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>;</p></li>
</ul></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.4)</a></span>
otherwise,
<code>submdspan_mapping_result{layout_stride::mapping(sub_ext, sub_strides), offset}</code>.</p></li>
</ul>
</div>
</div>
</body>
</html>
