<!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="2024-07-11" />
  <title>aligned_accessor: An mdspan accessor expressing pointer overalignment</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"><code>aligned_accessor</code>:
An mdspan accessor expressing pointer overalignment</h1>

<table style="border:none;float:right">
  <tr>
    <td>Document #: </td>
    <td>P2897R2</td>
  </tr>
  <tr>
    <td>Date: </td>
    <td>2024-07-11</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project: </td>
    <td>Programming Language C++<br>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to: </td>
    <td>
      Mark Hoemmen<br>&lt;<a href="mailto:mhoemmen@nvidia.com" class="email">mhoemmen@nvidia.com</a>&gt;<br>
      Damien Lebrun-Grandie<br>&lt;<a href="mailto:lebrungrandt@ornl.gov" class="email">lebrungrandt@ornl.gov</a>&gt;<br>
      Nicolas Morales<br>&lt;<a href="mailto:nmmoral@sandia.gov" class="email">nmmoral@sandia.gov</a>&gt;<br>
      Christian Trott<br>&lt;<a href="mailto:crtrott@sandia.gov" class="email">crtrott@sandia.gov</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></li>
<li><a href="#purpose-of-this-paper" id="toc-purpose-of-this-paper"><span class="toc-section-number">3</span>
Purpose of this paper</a></li>
<li><a href="#key-features" id="toc-key-features"><span class="toc-section-number">4</span> Key features</a></li>
<li><a href="#design-discussion" id="toc-design-discussion"><span class="toc-section-number">5</span> Design discussion</a>
<ul>
<li><a href="#the-accessor-is-not-nestable" id="toc-the-accessor-is-not-nestable"><span class="toc-section-number">5.1</span> The accessor is not
nestable</a></li>
<li><a href="#explicit-constructor-from-default_accessor" id="toc-explicit-constructor-from-default_accessor"><span class="toc-section-number">5.2</span> Explicit constructor from
<code>default_accessor</code></a></li>
<li><a href="#why-no-explicit-constructor-from-less-to-more-alignment" id="toc-why-no-explicit-constructor-from-less-to-more-alignment"><span class="toc-section-number">5.3</span> Why no explicit constructor from
less to more alignment?</a></li>
<li><a href="#we-do-not-define-an-alias-for-aligned-mdspan" id="toc-we-do-not-define-an-alias-for-aligned-mdspan"><span class="toc-section-number">5.4</span> We do not define an alias for
aligned mdspan</a></li>
<li><a href="#mdspan-construction-safety" id="toc-mdspan-construction-safety"><span class="toc-section-number">5.5</span> mdspan construction
safety</a></li>
<li><a href="#is_sufficiently_aligned-is-not-constexpr" id="toc-is_sufficiently_aligned-is-not-constexpr"><span class="toc-section-number">5.6</span>
<code>is_sufficiently_aligned</code> is not
<code>constexpr</code></a></li>
<li><a href="#generalize-is_sufficiently_aligned-for-all-accessors" id="toc-generalize-is_sufficiently_aligned-for-all-accessors"><span class="toc-section-number">5.7</span> Generalize
<code>is_sufficiently_aligned</code> for all accessors?</a>
<ul>
<li><a href="#is_sufficiently_aligned-is-specific-to-aligned_accessor" id="toc-is_sufficiently_aligned-is-specific-to-aligned_accessor"><span class="toc-section-number">5.7.1</span>
<code>is_sufficiently_aligned</code> is specific to
<code>aligned_accessor</code></a></li>
<li><a href="#detectably_invalid-generic-validity-check" id="toc-detectably_invalid-generic-validity-check"><span class="toc-section-number">5.7.2</span> <code>detectably_invalid</code>:
Generic validity check?</a></li>
<li><a href="#arguments-against-and-for-detectably_invalid" id="toc-arguments-against-and-for-detectably_invalid"><span class="toc-section-number">5.7.3</span> Arguments against and for
<code>detectably_invalid</code></a></li>
<li><a href="#nonmember-customization-point-design" id="toc-nonmember-customization-point-design"><span class="toc-section-number">5.7.4</span> Nonmember customization point
design</a></li>
<li><a href="#we-need-both-is_sufficiently_aligned-and-detectably_invalid" id="toc-we-need-both-is_sufficiently_aligned-and-detectably_invalid"><span class="toc-section-number">5.7.5</span> We need both
<code>is_sufficiently_aligned</code> and
<code>detectably_invalid</code></a></li>
<li><a href="#alternative-nonmember-is_sufficiently_aligned" id="toc-alternative-nonmember-is_sufficiently_aligned"><span class="toc-section-number">5.7.6</span> Alternative: Nonmember
<code>is_sufficiently_aligned</code></a></li>
<li><a href="#do-accessors-need-to-check-anything-else" id="toc-do-accessors-need-to-check-anything-else"><span class="toc-section-number">5.7.7</span> Do accessors need to check
anything else?</a></li>
<li><a href="#naming-the-function" id="toc-naming-the-function"><span class="toc-section-number">5.7.8</span> Naming the function</a></li>
<li><a href="#conclusions" id="toc-conclusions"><span class="toc-section-number">5.7.9</span> Conclusions</a></li>
</ul></li>
<li><a href="#explicit-conversions-as-the-model-for-precondition-asserting-conversions" id="toc-explicit-conversions-as-the-model-for-precondition-asserting-conversions"><span class="toc-section-number">5.8</span> Explicit conversions as the model
for precondition-asserting conversions</a>
<ul>
<li><a href="#example-conversion-to-aligned_accessor" id="toc-example-conversion-to-aligned_accessor"><span class="toc-section-number">5.8.1</span> Example: conversion to
<code>aligned_accessor</code></a></li>
<li><a href="#status-quo" id="toc-status-quo"><span class="toc-section-number">5.8.2</span> Status quo</a></li>
<li><a href="#mdspan-uses-explicit-conversions-to-assert-preconditions" id="toc-mdspan-uses-explicit-conversions-to-assert-preconditions"><span class="toc-section-number">5.8.3</span> <code>mdspan</code> uses
explicit conversions to assert preconditions</a></li>
<li><a href="#alternative-explicit-cast-function-naughty_cast" id="toc-alternative-explicit-cast-function-naughty_cast"><span class="toc-section-number">5.8.4</span> Alternative: explicit cast
function <code>naughty_cast</code></a></li>
<li><a href="#conclusion-retain-mdspans-current-design" id="toc-conclusion-retain-mdspans-current-design"><span class="toc-section-number">5.8.5</span> Conclusion: retain
<code>mdspan</code>’s current design</a></li>
</ul></li>
</ul></li>
<li><a href="#implementation" id="toc-implementation"><span class="toc-section-number">6</span> Implementation</a></li>
<li><a href="#example" id="toc-example"><span class="toc-section-number">7</span> Example</a></li>
<li><a href="#references" id="toc-references"><span class="toc-section-number">8</span> References</a></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">9</span> Acknowledgments</a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">10</span> Wording</a>
<ul>
<li><a href="#add-subsection-mdspan.accessor.aligned-with-the-following" id="toc-add-subsection-mdspan.accessor.aligned-with-the-following"><span class="toc-section-number">10.1</span> Add subsection �
[mdspan.accessor.aligned] with the following</a></li>
<li><a href="#members-mdspan.accessor.aligned.members" id="toc-members-mdspan.accessor.aligned.members"><span class="toc-section-number">10.2</span> Members
[mdspan.accessor.aligned.members]</a></li>
</ul></li>
<li><a href="#wording-for-alternative-nonmember-is_sufficiently_aligned-design" id="toc-wording-for-alternative-nonmember-is_sufficiently_aligned-design"><span class="toc-section-number">11</span> Wording for alternative nonmember
<code>is_sufficiently_aligned</code> design</a></li>
<li><a href="#appendix-a-detectably_invalid-nonmember-function-example" id="toc-appendix-a-detectably_invalid-nonmember-function-example"><span class="toc-section-number">12</span> Appendix A:
<code>detectably_invalid</code> nonmember function example</a></li>
<li><a href="#appendix-b-implementation-and-demo" id="toc-appendix-b-implementation-and-demo"><span class="toc-section-number">13</span> Appendix B: Implementation and
demo</a></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>Damien Lebrun-Grandie (lebrungrandt@ornl.gov) (Oak Ridge National
Laboratory)</p></li>
<li><p>Nicolas Morales (nmmoral@sandia.gov) (Sandia National
Laboratories)</p></li>
<li><p>Christian Trott (crtrott@sandia.gov) (Sandia National
Laboratories)</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>
<ul>
<li><p>Revision 0 (pre-Varna) to be submitted 2023-05-19</p></li>
<li><p>Revision 1 (pre-Kona) to be submitted 2023-10-15</p>
<ul>
<li><p>Implement changes requested by LEWG review on 2023-10-10</p>
<ul>
<li><p>Change <code>gcd</code> converting constructor Constraint to a
Mandate</p></li>
<li><p>Add Example in the wording section that uses
<code>is_sufficiently_aligned</code> to check the pointer overalignment
precondition</p></li>
<li><p>Add Example in the wording section that uses
<code>aligned_alloc</code> to create an overaligned allocation, to show
that <code>aligned_accessor</code> exists as part of a system</p></li>
<li><p>Add an <code>explicit</code> constructor from default_accessor,
so that users can type <code>aligned_mdspan y{x}</code> instead of
<code>aligned_mdspan y{x.data_handle(), x.mapping()}</code>. Add an
explanation in the design discussion section.</p></li>
</ul></li>
<li><p>Implement other wording changes</p>
<ul>
<li>Add to <code>aligned_accessor</code>’s Mandates that
<code>byte_alignment &gt;= alignof(ElementType)</code> is
<code>true</code>. This prevents construction of an invalid
<code>aligned_accessor</code> object.</li>
</ul></li>
<li><p>Add more design discussion based on LEWG review on 2023-10-10</p>
<ul>
<li><p>Explain why we do not include an <code>aligned_mdspan</code>
alias</p></li>
<li><p>Explain <code>aligned_accessor</code> construction
safety</p></li>
</ul></li>
</ul></li>
<li><p>Revision 2 (post - St. Louis) to be submitted 2024-07-15</p>
<ul>
<li><p>Implement required changes from LEWG review of R1 on
2024-06-28</p>
<ul>
<li>Remove <code>constexpr</code> from
<code>is_sufficiently_aligned</code></li>
</ul></li>
<li><p>Discuss optional suggestions from LEWG review of R1 on
2024-06-28</p>
<ul>
<li><p>Add <code>explicit</code> converting constructor vs. named cast
(“<code>naughty_cast</code>”) discussion</p></li>
<li><p>Add <code>detectably_invalid</code> discussion</p></li>
<li><p>Ask LEWG to consider the alternative design that makes
<code>is_sufficiently_aligned</code> a nonmember function in
<code>&lt;bit&gt;</code> instead of a member function of
<code>aligned_accessor</code>, while LWG review of R2 proceeds
concurrently</p></li>
</ul></li>
<li><p>P2389R2 was voted into the Working Draft at St. Louis, so replace
use of <code>dextents</code> in examples with
<code>dims</code>.</p></li>
<li><p>Add non-wording section explaining why
<code>aligned_accessor</code> has no <code>explicit</code> constructor
from less to more alignment</p></li>
<li><p>Add Compiler Explorer link with full implementation and
demo</p></li>
</ul></li>
</ul>
<h1 data-number="3" id="purpose-of-this-paper"><span class="header-section-number">3</span> Purpose of this paper<a href="#purpose-of-this-paper" class="self-link"></a></h1>
<p>We propose adding <code>aligned_accessor</code> to the C++ Standard
Library. This class template is an <code>mdspan</code> accessor policy
that uses <code>assume_aligned</code> to decorate pointer access. We
think it belongs in the Standard Library for two reasons. First, it
would serve as a common vocabulary type for interfaces that take
<code>mdspan</code> to declare their minimum alignment requirements.
Second, it extends to <code>mdspan</code> accesses the optimizations
that compilers can perform to pointers decorated with
<code>assume_aligned</code>.</p>
<p><code>aligned_accessor</code> is analogous to the various
<code>atomic_accessor_*</code> templates proposed by P2689. Both that
proposal and this one start with a Standard Library feature that
operates on a “raw” pointer (<code>assume_aligned</code> or the various
<code>atomic_ref*</code> templates), and then propose an
<code>mdspan</code> accessor policy that straightforwardly wraps the
lower-level feature.</p>
<p>We had originally written <code>aligned_accessor</code> as an example
in P2642, which proposes “padded” mdspan layouts. We realized that
<code>aligned_accessor</code> was more generally applicable and that
standardization would help the padded layouts proposed by P2642 reach
their maximum value.</p>
<h1 data-number="4" id="key-features"><span class="header-section-number">4</span> Key features<a href="#key-features" class="self-link"></a></h1>
<ul>
<li><p><code>offset_policy</code> is
<code>default_accessor</code></p></li>
<li><p><code>data_handle_type</code> is
<code>ElementType*</code></p></li>
<li><p>Permitted implicit conversions</p>
<ul>
<li><p>from nonconst to const <code>ElementType</code>,</p></li>
<li><p>from more overalignment to less overalignment, and</p></li>
<li><p>from overalignment to no overalignment
(<code>default_accessor</code>)</p></li>
</ul></li>
<li><p><code>explicit</code> converting constructor from
<code>default_accessor</code> lets users assert overalignment</p></li>
<li><p><code>is_sufficiently_aligned</code> checks pointer
alignment</p></li>
</ul>
<p>The <code>offset_policy</code> alias is
<code>default_accessor&lt;ElementType&gt;</code>, because even if a
pointer <code>p</code> is aligned, <code>p + i</code> might not be.</p>
<p>The <code>data_handle_type</code> alias is <code>ElementType*</code>.
It needs no further adornment, because alignment is asserted at the
point of access, namely in the <code>access</code> function. Some
implementations might have an easier time optimizing if they also apply
some implementation-specific attribute to <code>data_handle_type</code>
itself. Examples of such attributes include
<code>__declspec(align_value(byte_alignment))</code> and
<code>__attribute__((align_value(byte_alignment)))</code>. However,
these attributes should not apply to the result of <code>offset</code>,
for the same reason that <code>offset_policy</code> is
<code>default_accessor</code> and not <code>aligned_accessor</code>.</p>
<p>The converting constructor from <code>aligned_accessor</code> is
analogous to <code>default_accessor</code>’s constructor, in that it
exists to permit conversion from nonconst <code>element_type</code> to
const <code>element_type</code>. It additionally permits implicit
conversion from more overalignment to less overalignment – something
that we expect users may need to do. For example, users may start with
<code>aligned_accessor&lt;float, 128&gt;</code>, because their
allocation function promises 128-byte alignment. However, they may then
need to call a function that takes an <code>mdspan</code> with
<code>aligned_accessor&lt;float, 32&gt;</code>, which declares the
function’s intent to use 8-wide SIMD of <code>float</code>.</p>
<p>The <code>is_sufficiently_aligned</code> function checks whether a
pointer has sufficient alignment to be used correctly with the class.
This makes it easier for users to check preconditions, without needing
to know how to cast a pointer to an integer of the correct size and
signedness.</p>
<p>Per discussion below, we would like LEWG to consider the alternative
design that removes <code>is_sufficiently_aligned</code> from
<code>aligned_accessor</code> and adds it to the
<code>&lt;bit&gt;</code> header as a separate nonmember function. We
think LWG review of <code>aligned_accessor</code> can proceed
concurrently. We present wording for this design alternative below.</p>
<h1 data-number="5" id="design-discussion"><span class="header-section-number">5</span> Design discussion<a href="#design-discussion" class="self-link"></a></h1>
<h2 data-number="5.1" id="the-accessor-is-not-nestable"><span class="header-section-number">5.1</span> The accessor is not nestable<a href="#the-accessor-is-not-nestable" class="self-link"></a></h2>
<p>We considered making <code>aligned_accessor</code> “wrap” any
accessor type that meets the right requirements. For example,
<code>aligned_accessor</code> could take the inner accessor as a
template parameter, store an instance of it, and dispatch to its member
functions. That would give users a way to apply multiple accessor
“attributes” to their data handle, such as atomic access (see P2689) and
overalignment.</p>
<p>We decided against this approach for three reasons. First, we would
have no way to validate that the user’s accessor type has the correct
behavior. We could check that their accessor’s
<code>data_handle_type</code> is a pointer type, but we could not check
that their accessor’s <code>access</code> function actually dereferences
the pointer. For instance, <code>access</code> might instead interpret
the pointer as a file handle or a key into a distributed data store.</p>
<p>Second, even if the inner accessor’s <code>access</code> function
actually did return the result of dereferencing the pointer, the outer
<code>access</code> function might not be able to recover the effects of
the inner <code>access</code> function, because <code>access</code>
computes a <code>reference</code>, not a pointer. In order for
<code>aligned_accessor</code>’s <code>access</code> function to get back
that pointer, it would need to reach past the inner accessor’s public
interface. That would defeat the purpose of generic nesting.</p>
<p>Third, any way (not just this one) of nesting two generic accessors
raises the question of order dependence. Even if it were possible to
apply the effects of both the inner and outer accessors’
<code>access</code> functions in sequence, it might be unpleasantly
surprising to users if the effects depended on the order of nesting. A
similar question came up in the “properties” proposal P0900, which we
quote here.</p>
<blockquote>
<p>Practically speaking, it would be considered a best practice of a
high-quality implementation to ensure that a property’s implementation
of <code>properties::element_type_t</code> (and other traits) are
invariant with respect to ordering with other known properties (such as
those in the standard library), but with this approach it would be
impossible to make that guarantee formal, particularly with respect to
other vendor-defined and user-defined properties unknown to the property
implementer.</p>
</blockquote>
<p>For these reasons, we have made <code>aligned_accessor</code>
stand-alone, instead of having it modify another user-provided
accessor.</p>
<h2 data-number="5.2" id="explicit-constructor-from-default_accessor"><span class="header-section-number">5.2</span> Explicit constructor from
<code>default_accessor</code><a href="#explicit-constructor-from-default_accessor" class="self-link"></a></h2>
<p>LEWG’s 2023-10-10 review of R0 pointed out that in R0,
<code>aligned_accessor</code> lacks an <code>explicit</code> constructor
from <code>default_accessor</code>. Having that constructor would make
it easier for users to create an aligned <code>mdspan</code> from an
unaligned <code>mdspan</code>. Making it <code>explicit</code> would
prevent implicit conversion. Thus, we have decided to add this
<code>explicit</code> constructor in R1.</p>
<p>Without the <code>explicit</code> constructor, users have two options
for turning a nonaligned <code>mdspan</code> into an aligned
<code>mdspan</code>. First, as in the following example, users could
“take apart” the input nonaligned <code>mdspan</code> and use the pieces
to construct an aligned <code>mdspan</code>, whose type they name
completely.</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="dt">void</span> compute_with_aligned<span class="op">(</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> aligned_matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>,</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>layout_left, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a>  aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()}</span>;</span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Second, as in the following example, users could construct an
<code>aligned_accessor</code> explicitly and use constructor template
argument deduction (CTAD) to construct the aligned <code>mdspan</code>
from its pieces.</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><span class="dt">void</span> compute_with_aligned<span class="op">(</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    std<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="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The first approach would likely be more common. This is because
<code>mdspan</code> users commonly define their own type aliases for
<code>mdspan</code>, with application-specific names that make code more
self-documenting. The <code>aligned_matrix_t</code> definition above is
an an example.</p>
<p>Adding an <code>explicit</code> constructor from
<code>default_accessor</code> lets users get the same effect more
concisely, without needing to “take apart” the input
<code>mdspan</code>.</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><span class="dt">void</span> compute_with_aligned<span class="op">(</span>std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span>, <span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span> matrix<span class="op">)</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> std<span class="op">::</span><span class="dt">size_t</span> byte_alignment <span class="op">=</span> <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)</span>;</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>layout_left, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan aligned_matrix<span class="op">{</span>matrix<span class="op">}</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... use aligned_matrix ...</span></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>The <code>explicit</code> constructor does not decrease safety, in
the sense that users were always allowed to convert from an
<code>mdspan</code> with <code>default_accessor</code> to an
<code>mdspan</code> with <code>aligned_accessor</code>. Before, users
could perform this conversion by typing the following.</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>aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">.</span>data_handle<span class="op">()</span>, matrix<span class="op">.</span>mapping<span class="op">()}</span>;</span></code></pre></div>
<p>Now, users can do the same thing with fewer characters.</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>aligned_matrix_t aligned_matrix<span class="op">{</span>matrix<span class="op">}</span>;</span></code></pre></div>
<h2 data-number="5.3" id="why-no-explicit-constructor-from-less-to-more-alignment"><span class="header-section-number">5.3</span> Why no explicit constructor
from less to more alignment?<a href="#why-no-explicit-constructor-from-less-to-more-alignment" class="self-link"></a></h2>
<p>As explained in the previous section, <code>aligned_accessor</code>
has an <code>explicit</code> converting constructor from
<code>default_accessor</code> so that users can assert overalignment. It
also has an (implicit) converting constructor from another
<code>aligned_accessor</code> with more alignment, to an
<code>aligned_accessor</code> with less alignment. However,
<code>aligned_accessor</code> does <em>not</em> have an
<code>explicit</code> converting constructor from another
<code>aligned_accessor</code> with <em>less</em> alignment, to an
<code>aligned_accessor</code> with <em>more</em> alignment. Why not?</p>
<p>Consider the three typical use cases for
<code>aligned_accessor</code>.</p>
<ol type="1">
<li><p>User knows an allocation’s alignment at compile time.</p></li>
<li><p>User knows an allocation’s alignment at run time, but not at
compile time. For example, the value might depend on run-time detection
of particular hardware features.</p></li>
<li><p>User doesn’t know whether an allocation is overaligned. They
might need to ask some system at run time, or check the pointer value
themselves, in order to decide whether to call code that expects a
particular alignment.</p></li>
</ol>
<p>In Case (1), users would normally declare the maximum alignment. They
would want to preserve this information at compile time as much as
possible, by keeping the <code>aligned_accessor</code>
<code>mdspan</code> with maximum compile-time alignment for the entire
scope of its use. Users would only want implicit conversions to less
alignment or <code>default_accessor</code> when calling functions whose
parameter types encode these requirements.</p>
<p>Case (2) reduces to Case (3).</p>
<p>Case (3) reduces to Case (1). This works like any conversion from
run-time type to compile-time type, with a fixed list of possible
compile-time types (the alignments). As soon as a user’s
<code>mdspan</code> enters a scope where the alignment is known at
compile time, the user would want to preserve that compile-time
information and maximize the alignment for as large of a scope as
possible.</p>
<p>None of these cases involve starting with more alignment, going to
less (but still some) alignment, and then going back to more alignment
again. Code that does that probably does not correctly use the types of
function parameters to express its overalignment requirements. It’s like
code that uses <code>dynamic_cast</code> a lot. Users can still convert
from less or more alignment by creating the result’s
<code>aligned_accessor</code> manually. However, we don’t want to
encourage this pattern, so we don’t offer an explicit conversion for
it.</p>
<h2 data-number="5.4" id="we-do-not-define-an-alias-for-aligned-mdspan"><span class="header-section-number">5.4</span> We do not define an alias for
aligned mdspan<a href="#we-do-not-define-an-alias-for-aligned-mdspan" class="self-link"></a></h2>
<p>In LEWG’s 2023-10-10 review of R0, participants observed that this
proposal’s examples define an example-specific type alias for
<code>mdspan</code> with <code>aligned_accessor</code>. They asked
whether our proposal should include a <em>standard</em> alias
<code>aligned_mdspan</code>. We do not <em>object</em> to such an alias,
but we do not find it very useful, for the following reasons.</p>
<ol type="1">
<li><p>Users of <code>mdspan</code> commonly define their own type
aliases whose names are meaningful for their applications.</p></li>
<li><p>It would not save much typing.</p></li>
</ol>
<p>Examples may define aliases to make them more concise. One example in
this proposal defines the following alias for an <code>mdspan</code> of
<code>float</code> with alignment <code>byte_alignment</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="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>layout_right, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>This lets the example use <code>aligned_mdspan&lt;32&gt;</code> and
<code>aligned_mdspan&lt;16&gt;</code>.</p>
<p>The above alias is specific to a particular example. A
<em>general</em> version of alias would look like this.</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> ElementType, <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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType, Extents, Layout,</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>This alias would save <em>some</em> typing. However, mdspan “power
users” rarely type out all the template arguments. First, they can rely
on CTAD to create <code>mdspan</code>s, and <code>auto</code> to return
them. Second, users commonly already define their own aliases whose
names have an application-specific meaning. They define these aliases
<em>once</em> and use them throughout the application. For instance,
users might define the following.</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> ElementType<span class="op">&gt;</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> vector_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span>;</span>
<span id="cb8-4"><a href="#cb8-4" 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="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left<span class="op">&gt;</span>;</span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-8"><a href="#cb8-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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_vector_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left, </span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb8-12"><a href="#cb8-12" 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="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_matrix_t <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span>ElementType,</span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">2</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_left, </span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span>ElementType, byte_alignment<span class="op">&gt;&gt;</span>;</span></code></pre></div>
<p>Such users may never type the characters “<code>mdspan</code>” again.
For this reason, while we do not object to an
<code>aligned_mdspan</code> alias, we do not find the proliferation of
aliases particularly ergonomic.</p>
<h2 data-number="5.5" id="mdspan-construction-safety"><span class="header-section-number">5.5</span> mdspan construction safety<a href="#mdspan-construction-safety" class="self-link"></a></h2>
<p>LEWG’s 2023-10-10 review of R0 expressed concern that
<code>mdspan</code>’s constructor has no way to check
<code>aligned_accessor</code>’s alignment requirements. Users can call
<code>aligned_accessor</code>’s <code>is_sufficiently_aligned(p)</code>
<code>static</code> member function with a pointer <code>p</code> to
check this themselves, before constructing the <code>mdspan</code>.
However, <code>mdspan</code>’s constructor generally has no way to check
whether its accessor finds the caller’s data handle acceptable.</p>
<p>This is true for any accessor type, not just for
<code>aligned_accessor</code>. It is a design feature of
<code>mdspan</code> that accessors can be stateless. Most of them have
no state. Even if they have state, they do not need to be constructed
with or store the data handle. As a result, an accessor might not see a
data handle until <code>access</code> or <code>offset</code> is called.
Both of those member functions are performance critical, so they cannot
afford an extra branch on every call. Compare to
<code>vector::operator[]</code>, which has preconditions but is not
required to perform bounds checks. Using exceptions in the manner of
<code>vector::at</code> could reduce performance and would also make
<code>mdspan</code> unusable in a freestanding or no-exceptions
context.</p>
<p>Note that <code>aligned_accessor</code> does not introduce
<em>additional</em> preconditions beyond those of the existing C++
Standard Library feature <code>assume_aligned</code>. In the words of
one LEWG reviewer, <code>aligned_accessor</code> is not any more
“pointy” than <code>assume_aligned</code>; it just passes the point
through without “blunting” it.</p>
<p>Before submitting R0 of this paper, we considered an approach
specific to <code>aligned_accessor</code>, that would wrap the pointer
in a special data handle type. The data handle type would have an
<code>explicit</code> constructor that takes a raw pointer, with a
precondition that the raw pointer have sufficient alignment. The
constructor would be <code>explicit</code>, because it would have a
precondition. This design would force the precondition back to
<code>mdspan</code> construction time. Users would have to construct the
<code>mdspan</code> like this.</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>element_type<span class="op">*</span> raw_pointer <span class="op">=</span> get_pointer_from_somewhere<span class="op">()</span>;</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> acc_type <span class="op">=</span> aligned_accessor<span class="op">&lt;</span>element_type, byte_alignment<span class="op">&gt;</span>;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>mdspan x<span class="op">{</span>acc_type<span class="op">::</span>data_handle_type<span class="op">{</span>raw_pointer<span class="op">}</span>, mapping, acc_type<span class="op">{}}</span>;</span></code></pre></div>
<p>We rejected this approach in favor of
<code>is_sufficiently_aligned</code> for the following reasons.</p>
<ol type="1">
<li><p>Wrapping the pointer in a custom data handle class would make
every <code>access</code> or <code>offset</code> call need to reach
through the data handle’s interface, instead of just taking the raw
pointer directly. The <code>access</code> function, and to some extent
also <code>offset</code>, need to be as fast as possible. Their
performance depends on compilers being able to optimize through function
calls. The authors of <code>mdspan</code> carefully balanced generality
with function call depth and other code complexity factors that may
hinder compilers from optimizing. Performance of
<code>aligned_accessor</code> matters as much or even more than
performance of <code>default_accessor</code>, because
<code>aligned_accessor</code> exists to communicate optimization
potential.</p></li>
<li><p>The alignment precondition would still exist. Requiring the data
handle type to throw an exception if the pointer is not sufficiently
aligned would make <code>mdspan</code> unusable in a freestanding or
no-exceptions context.</p></li>
<li><p>Users should not have to pay for unneeded checks. The two
examples in the wording express the two most common cases. If users get
a pointer from a function like <code>aligned_alloc</code>, then they
already know its alignment, because they asked for it. If users are
computing alignment at run time to dispatch to a more optimized code
path, then they know alignment before dispatch. In both cases, users
already know the alignment before constructing the
<code>mdspan</code>.</p></li>
<li><p>The data handle is still a pointer, it’s just a pointer with a
constraint on its values. Users would reasonably expect to be able to
use the result of <code>data_handle()</code> with existing interfaces
that expect a raw pointer.</p></li>
</ol>
<p>An LEWG poll on 2023-10-10, “[b]lock <code>aligned_accessor</code>
progressing until we have a way of checking alignment requirements
during <code>mdspan</code> construction,” resulted in no consensus.
Attendance was 14.</p>
<table>
<tr>
<th>
Strongly Favor
</th>
<th>
Weakly Favor
</th>
<th>
Neutral
</th>
<th>
Weakly Against
</th>
<th>
Strongly Against
</th>
</tr>
<tr>
<th>
0
</th>
<th>
1
</th>
<th>
1
</th>
<th>
2
</th>
<th>
2
</th>
</tr>
</table>
<p>LEWG expressed an (unpolled) interest that we explore
<code>mdspan</code> safety in subsequent work after the fall 2023 Kona
WG21 meeting. LEWG asked us to explore safety in a way that is not
specific to <code>aligned_accessor</code>. Part of that exploration is
in the section below “Generalize <code>is_sufficiently_aligned</code>
for all accessors?”. We plan further exploration of this topic
elsewhere.</p>
<h2 data-number="5.6" id="is_sufficiently_aligned-is-not-constexpr"><span class="header-section-number">5.6</span>
<code>is_sufficiently_aligned</code> is not <code>constexpr</code><a href="#is_sufficiently_aligned-is-not-constexpr" class="self-link"></a></h2>
<p>LEWG reviewed R1 of this proposal at the June 2024 St. Louis WG21
meeting, and polled 1/10/0/0/1 (SF/F/N/A/SA) to remove
<code>constexpr</code> from <code>is_sufficiently_aligned</code>. This
is because it is not clear how to implement the function in a way that
could ever be a constant expression. The straightforward cross-platform
way to implement this would <code>bit_cast</code> the pointer to
<code>uintptr_t</code>. However, <code>bit_cast</code> is not
<code>constexpr</code> when converting from a pointer to an integer, per
<a href="https://eel.is/c++draft/bit.cast#3">[bit.cast] 3</a>. Any
<code>reinterpret_cast</code> similarly could not be a core constant
expression, per
<a href="https://eel.is/c++draft/expr.const#5.15">[expr.const] 5.15</a>.
One LEWG reviewer pointed out that some compilers have a built-in
operation (e.g., Clang and GCC have <code>__builtin_bit_cast</code>)
that might form a constant expression when <code>bit_cast</code> does
not. On the other hand, the authors could not foresee a need for
<code>is_sufficiently_aligned</code> to be <code>constexpr</code> and
did not want to constrain implementations to use compiler-specific
functionality.</p>
<h2 data-number="5.7" id="generalize-is_sufficiently_aligned-for-all-accessors"><span class="header-section-number">5.7</span> Generalize
<code>is_sufficiently_aligned</code> for all accessors?<a href="#generalize-is_sufficiently_aligned-for-all-accessors" class="self-link"></a></h2>
<h3 data-number="5.7.1" id="is_sufficiently_aligned-is-specific-to-aligned_accessor"><span class="header-section-number">5.7.1</span>
<code>is_sufficiently_aligned</code> is specific to
<code>aligned_accessor</code><a href="#is_sufficiently_aligned-is-specific-to-aligned_accessor" class="self-link"></a></h3>
<p>The <code>is_sufficiently_aligned</code> function exists so users can
check the pointer’s alignment precondition before constructing an
<code>mdspan</code> with it. This precondition check is specific to
<code>aligned_accessor</code>. Furthermore, the function has a
precondition that the pointer points to a valid element. Standard C++
offers no way for users to check that. More importantly for
<code>mdspan</code> users, Standard C++ offers no way to check whether a
pointer and a layout mapping’s <code>required_span_size()</code> form a
valid range.</p>
<h3 data-number="5.7.2" id="detectably_invalid-generic-validity-check"><span class="header-section-number">5.7.2</span>
<code>detectably_invalid</code>: Generic validity check?<a href="#detectably_invalid-generic-validity-check" class="self-link"></a></h3>
<p>During the June 2024 St. Louis WG21 meeting, one LEWG reviewer
(please see Acknowledgments below) pointed out that code that is generic
on the accessor type currently has no way to check whether a given data
handle is valid. Specifically, given a <code>size_t</code>
<code>size</code> (e.g., the <code>required_span_size()</code> of a
given layout mapping), there is no way to check whether <span class="math inline">[</span> 0, <code>size</code> <span class="math inline">)</span> forms an accessible range (see
<a href="https://eel.is/c++draft/views.multidim#mdspan.accessor.general-2">[mdspan.accessor.general]
2</a>) of a given data handle and accessor. The reviewer suggested
adding a new member function</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="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type handle, <span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">const</span> <span class="kw">noexcept</span>;</span></code></pre></div>
<p>to all <code>mdspan</code> accessors. This would return
<code>true</code> if the implementation can show that <span class="math inline">[</span> 0, <code>size</code> <span class="math inline">)</span> is <em>not</em> an accessible range for
<code>handle</code> and the accessor, and <code>true</code> otherwise.
The word “detectably” in the name would remind users that this is a
“best effort” check. It might return <code>false</code> even if the
handle is invalid or if <span class="math inline">[</span> 0,
<code>size</code> <span class="math inline">)</span> is not an
accessible range. Also, it might return different values on different
implementations, depending on their ability to check e.g., pointer range
validity. The function would have the following design features.</p>
<ul>
<li><p>It must be a non-<code>static</code> member function, because in
general, accessors may have state that determines validity of the data
handle.</p></li>
<li><p>It must be <code>const</code> because precondition-checking code
should avoid observable side effects.</p></li>
<li><p>It must be <code>noexcept</code> because precondition-checking
code should not throw.</p></li>
</ul>
<p>With such a function, users could write generic checked
<code>mdspan</code> creation code like the following.</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> LayoutMapping, <span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> create_mdspan_with_check<span class="op">(</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type handle,</span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>  LayoutMapping mapping,</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>  Accessor accessor<span class="op">)</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>accessor<span class="op">.</span>detectably_invalid<span class="op">(</span>handle, mapping<span class="op">.</span>required_span_size<span class="op">()))</span> <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>out_of_range<span class="op">(</span><span class="st">&quot;Invalid data handle and/or size&quot;</span><span class="op">)</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> mdspan<span class="op">{</span>handle, mapping, accessor<span class="op">}</span>;</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.3" id="arguments-against-and-for-detectably_invalid"><span class="header-section-number">5.7.3</span> Arguments against and for
<code>detectably_invalid</code><a href="#arguments-against-and-for-detectably_invalid" class="self-link"></a></h3>
<p>We didn’t include this feature in the original <code>mdspan</code>
design because most data handle types have no way to say with full
accuracy whether a handle and size are valid. We didn’t want to give
users the false impression that a validity check was doing anything
meaningful. Standard C++ has no way to check a raw pointer
<code>T*</code> and a size, though some implementations such as CHERI
C++ ([Davis 2019] and [Watson 2020]) and run-time profiling and
debugging systems such as Valgrind do have this feature. We designed
<code>mdspan</code> accessors to be able to wrap libraries that
implement a partitioned global address space (PGAS) programming model
for accessing remote data over a network. (See
<a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0009r18.html#why-custom-accessors">P0009R18,
Section 2.7, “Why custom accessors?”.</a>) Such libraries include the
one-sided communication interface in MPI (the Message Passing Interface
for distributed-memory parallel programming) or NVSHMEM (NVIDIA’s
implementation of the SHMEM standard). Those libraries define their own
data handle to represent remote data. For example, MPI uses an
<code>MPI_Win</code> “window” object. NVSHMEM uses a C++ pointer to
represent a “symmetric address” that points to an allocation from the
“symmetric heap” (that is accessible to all participating parallel
processes). Such libraries generally do not have validity checks for
their handles.</p>
<p>On the other hand, a <code>detectably_invalid</code> function would
let happen any checks that <em>could</em> happen. For instance, a
hypothetical “GPU device memory accessor” (not proposed for the C++
Standard, but existing in projects like
<a href="https://github.com/rapidsai/raft">RAPIDS RAFT</a>) might permit
access to an allocation of GPU “device” memory from only GPU “device”
code, not from ordinary “host” code. A common use case for GPU
allocations is to allocate device memory in host code, then pass the
pointer to device code for use there. Thus, it would be reasonable to
create an <code>mdspan</code> in host code with that accessor. The
accessor could use a CUDA run-time function like
<a href="https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__UNIFIED.html"><code>cudaPointerGetAttributes</code></a>
to check if the pointer points to valid GPU memory. Even
<code>default_accessor</code> could have a simple check like this.</p>
<div class="sourceCode" id="cb12"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, <span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> ptr <span class="op">==</span> <span class="kw">nullptr</span> <span class="op">&amp;&amp;</span> size <span class="op">!=</span> <span class="dv">0</span>;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.4" id="nonmember-customization-point-design"><span class="header-section-number">5.7.4</span> Nonmember customization point
design<a href="#nonmember-customization-point-design" class="self-link"></a></h3>
<p>C++23 defines the generic interface of accessors through the accessor
policy requirements
<a href="https://eel.is/c++draft/mdspan.accessor.reqmts"><strong>[mdspan.accessor.reqmts]</strong></a>.
Adding <code>detectably_invalid</code> to these requirements would be a
breaking change to C++23. Thus, generic code that wanted to call this
function would need to fill in default behavior for both Standard
accessors defined in C++23, and user-defined accessors that comply with
the C++23 accessor requirements. The following
<code>detectably_invalid</code> nonmember function (not proposed in this
paper) shows one way users could do that. Please see Appendix A below
for the full source code of a demonstration, along with a Compiler
Explorer link. This demonstration shows that breaking backwards
compatibility with C++23 is unnecessary, because users can
straightforwardly work around the lack of a
<code>detectably_invalid</code> member function in C++23 - compliant
accessors. Not standardizing this nonmember function work-around would
also give users the freedom to fill in different default behavior. For
example, some users may prefer to consider every (data handle, size)
pair invalid unless proven otherwise, as a way to force use of custom
accessors that have the ability to make accurate checks.</p>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> has_detectably_invalid <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span>Accessor acc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> std<span class="op">::</span>as_const<span class="op">(</span>acc<span class="op">).</span>detectably_invalid<span class="op">(</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span><span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type<span class="op">&gt;()</span>,</span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;()</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span> <span class="op">}</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> std<span class="op">::</span>same_as<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>Accessor<span class="op">&amp;&amp;</span> accessor,</span>
<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;::</span>data_handle_type handle,</span>
<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span></span>
<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>has_detectably_invalid<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>as_const<span class="op">(</span>accessor<span class="op">).</span>detectably_invalid<span class="op">(</span>handle, size<span class="op">)</span>;</span>
<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h3 data-number="5.7.5" id="we-need-both-is_sufficiently_aligned-and-detectably_invalid"><span class="header-section-number">5.7.5</span> We need both
<code>is_sufficiently_aligned</code> and
<code>detectably_invalid</code><a href="#we-need-both-is_sufficiently_aligned-and-detectably_invalid" class="self-link"></a></h3>
<p>The same LEWG reviewer who suggested <code>detectably_invalid</code>
also said that it would make <code>is_sufficiently_aligned</code>
unnecessary. We disagree for the following reasons.</p>
<ol type="1">
<li><p>Users will often want to check alignment separately from pointer
range validity.</p></li>
<li><p>Checking alignment may be much less expensive than checking
pointer range validity.</p></li>
</ol>
<p>Regarding (1), we think the most common use case for
<code>aligned_accessor</code>’s <code>explicit</code> converting
constructor from <code>default_accessor</code> would be explicit
construction of an <code>mdspan</code> with
<code>aligned_accessor</code> from an <code>mdspan</code> with
<code>default_accessor</code>. The latter exists, so the user has
already asserted that the range formed by its data handle and
<code>required_span_size()</code> is valid. Thus, the only thing the
user would need to check would be whether the data handle is
sufficiently aligned.</p>
<h3 data-number="5.7.6" id="alternative-nonmember-is_sufficiently_aligned"><span class="header-section-number">5.7.6</span> Alternative: Nonmember
<code>is_sufficiently_aligned</code><a href="#alternative-nonmember-is_sufficiently_aligned" class="self-link"></a></h3>
<p>The reviewer responded to our argument above by suggesting that we
remove <code>is_sufficiently_aligned</code> from
<code>aligned_accessor</code> and make it a separate nonmember function.
This is a reasonable alternative suggestion. We think that LWG review of
<code>aligned_accessor</code> can proceed concurrently while LEWG
considers this alternative.</p>
<p>Into which header should this new function go? We think it belongs in
<code>&lt;bit&gt;</code>, because it is fundamentally a bit arithmetic
operation. There should be no reason why that could not be freestanding,
like everything else in the <code>&lt;bit&gt;</code> header. Another
option would be to put it in <code>&lt;memory&gt;</code> right after
<code>assume_aligned</code>, and to mark it as freestanding (since
<code>assume_aligned</code> is).</p>
<h3 data-number="5.7.7" id="do-accessors-need-to-check-anything-else"><span class="header-section-number">5.7.7</span> Do accessors need to check
anything else?<a href="#do-accessors-need-to-check-anything-else" class="self-link"></a></h3>
<p>The only other thing an accessor’s user might want to check besides a
(data handle, size) pair would be converting construction from another
type of accessor. All <code>mdspan</code> components –
<code>extents</code>, layout mappings, and accessors – implement
conversions with preconditions via <code>explicit</code> constructors.
(For more detail, please see the section below, “Explicit conversions as
the model for precondition-asserting conversions.”) Accessors do
<em>not</em> store their data handles, so the only reason to check
whether converting construction is valid would be if the input or result
accessor has separate run-time state. (Otherwise, the check could be a
constraint or <code>static_assert</code>.) It’s rare for an accessor to
need run-time state, so we don’t expect to need this feature in generic
code. It would also be a separable addition from the feature of checking
a data handle and size. Nevertheless, one could consider a design. We
would favor just overloading <code>detectably_invalid</code> for
accessors, as there would be no risk of ambiguity. Converting
constructors only take one argument, so there would be no ambiguity
between calling <code>detectably_invalid</code> with an accessor and
calling it with a data handle and size.</p>
<h3 data-number="5.7.8" id="naming-the-function"><span class="header-section-number">5.7.8</span> Naming the function<a href="#naming-the-function" class="self-link"></a></h3>
<ol type="1">
<li><p>The function describes a property: “this (data handle, size) pair
is not known to be invalid.” It’s an adjective (like
“<code>valid</code>” or “<code>is_valid</code>”), not a verb (like
“check” as in “<code>check_valid</code>”).</p></li>
<li><p>The function does not promise perfect accuracy. In the common
case, it says whether it can <em>detect</em> whether the handle and size
are _in_valid. Whether or not they are <em>valid</em> might be harder to
say.</p></li>
<li><p>As discussed above, users may also want to check converting
constructors from other accessor types. However, there would be no risk
of ambiguity between that and checking a data handle and size.
Therefore, there’s no need for the function’s name to include the type
of the thing being checked (e.g., “range”).</p></li>
<li><p>Specifically, the function should not contain the word “pointer,”
because a data handle is not necessarily a pointer. Even if
<code>data_handle_type</code>​ is a pointer type, a data handle might not
necessarily be a pointer to the elements in the Standard C++ sense. For
example, it might be some opaque handle that a library represents as a
type alias of <code>void*</code>​.</p></li>
</ol>
<p>These points together suggest the name
<code>detectably_invalid</code>.</p>
<h3 data-number="5.7.9" id="conclusions"><span class="header-section-number">5.7.9</span> Conclusions<a href="#conclusions" class="self-link"></a></h3>
<ol type="1">
<li><p>Adding <code>detectably_invalid</code> to the accessor
requirements and existing Standard accessors in C++26 would be a
breaking change to C++23. Nevertheless, users could write code that
fills in reasonable behavior for C++23 accessors.</p></li>
<li><p>Few C++ implementations offer a way to check validity of a
pointer range. Thus, users would experience
<code>detectably_invalid</code> as mostly not useful for the common case
of <code>default_accessor</code> and other accessors that access a
pointer range.</p></li>
<li><p>Item (1) reduces the urgency of this suggestion for C++26. Item
(2) reduces its potential to improve the <code>mdspan</code> user
experience in a practical way. Therefore, we do not suggest adding
<code>detectably_invalid</code> to the accessor requirements in this
proposal. However, we do not discourage further work in separate
proposals.</p></li>
<li><p>We would like LEWG to consider the alternative design that
removes <code>is_sufficiently_aligned</code> from
<code>aligned_accessor</code> and adds it to the C++ Standard Library as
a separate nonmember function. We think LWG review of
<code>aligned_accessor</code> can proceed concurrently.</p></li>
</ol>
<h2 data-number="5.8" id="explicit-conversions-as-the-model-for-precondition-asserting-conversions"><span class="header-section-number">5.8</span> Explicit conversions as the
model for precondition-asserting conversions<a href="#explicit-conversions-as-the-model-for-precondition-asserting-conversions" class="self-link"></a></h2>
<p>During the June 2024 St. Louis WG21 meeting, one LEWG reviewer asked
about the <code>explicit</code> constructor from
<code>default_accessor</code>. This constructor lets users assert that a
pointer has sufficient alignment to be accessed by the
<code>aligned_accessor</code>. The reviewer argued that this was an
“unsafe” conversion, and wanted these “unsafe” conversions to be even
more explicit than an <code>explicit</code> constructor: e.g., a new
<code>*_cast</code> function template. We do not agree with this idea;
this section explains why.</p>
<h3 data-number="5.8.1" id="example-conversion-to-aligned_accessor"><span class="header-section-number">5.8.1</span> Example: conversion to
<code>aligned_accessor</code><a href="#example-conversion-to-aligned_accessor" class="self-link"></a></h3>
<p>Suppose that some function that users can’t change returns an
<code>mdspan</code> of <code>float</code> with
<code>default_accessor</code>, even though users know that the
<code>mdspan</code> is overaligned to <code>8 * sizeof(float)</code>
bytes. The function’s parameter(s) don’t matter for this example.</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>mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right, default_accessor<span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;&gt;</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>  overaligned_view<span class="op">(</span>SomeParameters params<span class="op">)</span>;</span></code></pre></div>
<p>Suppose also that users want to call some other function that they
can’t change. This function takes an <code>mdspan</code> of
<code>float</code> with <code>aligned_accessor&lt;float, 8&gt;</code>.
Its return type doesn’t matter for this example.</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>SomeReturnType use_overaligned_view<span class="op">(</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right, aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;)</span>;</span></code></pre></div>
<h3 data-number="5.8.2" id="status-quo"><span class="header-section-number">5.8.2</span> Status quo<a href="#status-quo" class="self-link"></a></h3>
<p>How do users call <code>use_overaligned_view</code> with the object
returned from <code>overaligned_view</code>? The status quo offers two
ways. Both of them rely on
<code>aligned_accessor&lt;float, 8&gt;</code>’s <code>explicit</code>
converting constructor from
<code>default_accessor&lt;float&gt;</code>.</p>
<ol type="1">
<li><p>Use <code>mdspan</code>’s <code>explicit</code> converting
constructor.</p></li>
<li><p>Construct the new <code>mdspan</code> explicitly from its data
handle, layout mapping, and accessor. (This is the ideal use case for
CTAD, as an <code>mdspan</code> is nothing more than its data handle,
layout mapping, and accessor.)</p></li>
</ol>
<p>Way (1) looks like this.</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">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right,</span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">)</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Way (2) looks like this. Note use of CTAD.</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">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">.</span>accessor<span class="op">())}</span></span>
<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Which way is less verbose depends on <code>mdspan</code>’s template
arguments. Both ways, though, force the user to name the type
<code>aligned_accessor&lt;float, 8&gt;</code> explicitly. Users know
that they have pulled out a sharp knife from the toolbox. It’s verbose,
it’s nondefault, and it’s a class with a short definition. Users can go
to the specification, see <code>assume_aligned</code>, and know they are
dealing with a low-level function that has a precondition.</p>
<h3 data-number="5.8.3" id="mdspan-uses-explicit-conversions-to-assert-preconditions"><span class="header-section-number">5.8.3</span> <code>mdspan</code> uses
explicit conversions to assert preconditions<a href="#mdspan-uses-explicit-conversions-to-assert-preconditions" class="self-link"></a></h3>
<p>The entire system of <code>mdspan</code> components was designed so
that</p>
<ul>
<li><p>conversions with preconditions happen through
<code>explicit</code> conversions (mostly converting constructors);
while</p></li>
<li><p>conversions without preconditions happen through implicit
conversions.</p></li>
</ul>
<p>Changing this would break backwards compatibility with C++23. For
example, one can see this with converting constructors for</p>
<ul>
<li><p><code>extents</code> (for conversions from run-time to
compile-time extents, or conversions from wider to narrower index type):
<a href="https://eel.is/c++draft/mdspan.extents.cons">[mdspan.extents.cons]</a>;
and</p></li>
<li><p><code>layout_left::mapping</code>, and all the other layout
mappings currently in the Standard that are not
<code>layout_stride</code> or <code>layout_transpose</code> (for
conversions from e.g., <code>layout_stride::mapping</code>, which assert
that the strides are compatible): e.g.,
<a href="https://eel.is/c++draft/mdspan.layout.left.cons">[mdspan.layout.left.cons]</a>.</p></li>
</ul>
<p>This is consistent with C++ Standard Library class templates, in that
construction asserts any preconditions. For example, if users construct
a <code>string_view</code> or <code>span</code> from a pointer
<code>ptr</code> and a size <code>size</code>, this asserts that the
range <span class="math inline">[</span> <code>ptr</code>,
<code>ptr + size</code> <span class="math inline">)</span> is
accessible.</p>
<h3 data-number="5.8.4" id="alternative-explicit-cast-function-naughty_cast"><span class="header-section-number">5.8.4</span> Alternative: explicit cast
function <code>naughty_cast</code><a href="#alternative-explicit-cast-function-naughty_cast" class="self-link"></a></h3>
<p>Everything we have described above is the status quo. What did the
one LEWG reviewer want to see? They wanted all conversions with
preconditions to use a “cast” function with an easily searchable name,
analogous to <code>static_cast</code>. As a placeholder, we’ll call it
“<code>naughty_cast</code>.” For the above
<code>use_overaligned_view</code> example, the <code>naughty_cast</code>
analog of Way (2) would look like this.</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    naughty_cast<span class="op">&lt;</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;&gt;(</span>x<span class="op">.</span>accessor<span class="op">())}</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>One could imagine defining <code>naughty_cast</code> of
<code>mdspan</code> by <code>naughty_cast</code> of its components. This
would enable an analog of Way (1).</p>
<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">auto</span> x <span class="op">=</span> overaligned_view<span class="op">(</span>params<span class="op">)</span>;</span>
<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span>naughty_cast<span class="op">&lt;</span></span>
<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">&lt;</span><span class="dt">float</span>, dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, layout_right,</span>
<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;&gt;(</span>x<span class="op">)</span></span>
<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Another argument for <code>naughty_cast</code> besides searchability
is to make conversions with preconditions “loud,” that is, easily seen
in the code by human developers. However, the original Way (1) and Way
(2) both are loud already in that they require a lot of extra code that
spells out the result’s accessor type explicitly. The status quo’s
difference in “volume” is implicit conversion</p>
<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">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span>x<span class="op">)</span>;</span></code></pre></div>
<p>versus explicit construction.</p>
<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">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;(</span>x<span class="op">)})</span>;</span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>Adding <code>naughty_cast</code> to the latter doesn’t make it much
louder.</p>
<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">auto</span> result <span class="op">=</span> use_overaligned_view<span class="op">(</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a>  mdspan<span class="op">{</span>x<span class="op">.</span>data_handle<span class="op">()</span>, x<span class="op">.</span>mapping<span class="op">()</span>,</span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>    naughty_cast<span class="op">&lt;</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">8</span><span class="op">&gt;&gt;(</span>x<span class="op">)})</span>;</span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true" tabindex="-1"></a><span class="op">)</span>;</span></code></pre></div>
<p>There are other disadvantages to a <code>naughty_cast</code> design.
The point of that design would be to remove or make
non-<code>public</code> all the <code>explicit</code> constructors from
<code>mdspan</code>’s components. That functionality would need to move
somewhere. A typical implementation technique for a custom cast function
is to rely on specializations of a struct with two template parameters,
one for the input type and one for the output type of the cast. The
<code>naughty_caster</code> struct example below shows how one could do
that.</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Output, <span class="kw">class</span> Input<span class="op">&gt;</span></span>
<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> naughty_caster <span class="op">{}</span>;</span>
<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Output, <span class="kw">class</span> Input<span class="op">&gt;</span></span>
<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a>Output naughty_cast<span class="op">(</span><span class="kw">const</span> Input<span class="op">&amp;</span> input<span class="op">)</span> <span class="op">{</span></span>
<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> naughty_caster<span class="op">&lt;</span>Output, Input<span class="op">&gt;::</span>cast<span class="op">(</span>input<span class="op">)</span>;</span>
<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OutputElementType, <span class="dt">size_t</span> ByteAlignment,</span>
<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> InputElementType<span class="op">&gt;</span></span>
<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> <span class="op">(</span>is_convertible_v<span class="op">&lt;</span>InputElementType<span class="op">(*)[]</span>,</span>
<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a>    OutputElementType<span class="op">(*)[]&gt;)</span> </span>
<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> naughty_caster <span class="op">{</span></span>
<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> output_type <span class="op">=</span></span>
<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OutputElementType, ByteAlignment<span class="op">&gt;</span>;</span>
<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> input_type <span class="op">=</span> default_accessor<span class="op">&lt;</span>InputElementType<span class="op">&gt;</span>;</span>
<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> output_type cast<span class="op">(</span><span class="kw">const</span> input_type<span class="op">&amp;)</span> <span class="op">{</span></span>
<span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>; </span>
<span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p>This technique takes a lot of effort and code, when by far the common
case is that <code>cast</code> has a trivial body. For any accessors
with state, it would almost certainly call for breaks of encapsulation,
like making the <code>naughty_caster</code> specialization a
<code>friend</code> of the input and/or output.</p>
<p>We emphasize that users are meant to write custom accessors. The
intended typical author of a custom accessor is a performance expert who
is not necessarily a C++ expert. It takes quite a bit of C++ experience
to learn how to use encapsulation-breaking techniques safely; the lazy
approaches all just expose implementation details or defeat the “safety”
that <code>naughty_cast</code> is supposed to introduce. Given that the
main motivation of <code>naughty_cast</code> is safety, we shouldn’t
make it harder for users to write safe code.</p>
<p>More importantly, <code>naughty_cast</code> would obfuscate
accessors. The architects of <code>mdspan</code> meant accessors to have
to have a small number of “moving parts” and to define all those parts
in a single place. Contrast <code>default_accessor</code> with the
contiguous iterator requirements, for instance. The
<code>naughty_cast</code> design would force custom accessors (and
custom layouts) to define their different parts in different places,
rather than all in one class. WG21 has moved away from this scattered
design approach. For example,
<a href="https://wg21.link/p2855r1">P2855R1</a> (“Member customization
points for Senders and Receivers”) changes P2300 (std::execution) to use
member functions instead of <code>tag_invoke</code>-based customization
points.</p>
<h3 data-number="5.8.5" id="conclusion-retain-mdspans-current-design"><span class="header-section-number">5.8.5</span> Conclusion: retain
<code>mdspan</code>’s current design<a href="#conclusion-retain-mdspans-current-design" class="self-link"></a></h3>
<p>For all these reasons, we do not support replacing
<code>mdspan</code>’s current “conversions with preconditions are
explicit conversions” design with a cast function design.</p>
<h1 data-number="6" id="implementation"><span class="header-section-number">6</span> Implementation<a href="#implementation" class="self-link"></a></h1>
<p>We have tested an implementation of this proposal with the <a href="https://github.com/kokkos/mdspan/">reference mdspan
implementation</a>. Appendix B below lists the source code of a full
implementation.</p>
<h1 data-number="7" id="example"><span class="header-section-number">7</span> Example<a href="#example" class="self-link"></a></h1>
<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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span></span>
<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 32-byte alignment,</span></span>
<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 8-wide SIMD of float.</span></span>
<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> vectorized_axpy<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y, <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</span>;</span>
<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-10"><a href="#cb24-10" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 16-byte alignment,</span></span>
<span id="cb24-11"><a href="#cb24-11" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 4-wide SIMD of float.</span></span>
<span id="cb24-12"><a href="#cb24-12" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> fill_x<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb24-13"><a href="#cb24-13" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> fill_y<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> y<span class="op">)</span>;</span>
<span id="cb24-14"><a href="#cb24-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-15"><a href="#cb24-15" aria-hidden="true" tabindex="-1"></a><span class="co">// Helper functions for making overaligned array allocations.</span></span>
<span id="cb24-16"><a href="#cb24-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-17"><a href="#cb24-17" 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="cb24-18"><a href="#cb24-18" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb24-19"><a href="#cb24-19" 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="cb24-20"><a href="#cb24-20" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb24-21"><a href="#cb24-21" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb24-22"><a href="#cb24-22" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb24-23"><a href="#cb24-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-24"><a href="#cb24-24" 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="cb24-25"><a href="#cb24-25" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span> 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="cb24-26"><a href="#cb24-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-27"><a href="#cb24-27" 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="cb24-28"><a href="#cb24-28" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span> 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="cb24-29"><a href="#cb24-29" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb24-30"><a href="#cb24-30" 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="cb24-31"><a href="#cb24-31" 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="cb24-32"><a href="#cb24-32" 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="cb24-33"><a href="#cb24-33" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb24-34"><a href="#cb24-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-35"><a href="#cb24-35" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha<span class="op">)</span></span>
<span id="cb24-36"><a href="#cb24-36" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb24-37"><a href="#cb24-37" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Code using the above two interfaces needs to allocate to the max alignment.</span></span>
<span id="cb24-38"><a href="#cb24-38" aria-hidden="true" tabindex="-1"></a>  <span class="co">// Users could also query aligned_accessor::byte_alignment</span></span>
<span id="cb24-39"><a href="#cb24-39" aria-hidden="true" tabindex="-1"></a>  <span class="co">// for the various interfaces and take the max.</span></span>
<span id="cb24-40"><a href="#cb24-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb24-41"><a href="#cb24-41" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb24-42"><a href="#cb24-42" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb24-43"><a href="#cb24-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-44"><a href="#cb24-44" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb24-45"><a href="#cb24-45" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb24-46"><a href="#cb24-46" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-47"><a href="#cb24-47" aria-hidden="true" tabindex="-1"></a>  fill_x<span class="op">(</span>x<span class="op">)</span>; <span class="co">// automatic conversion from 32-byte aligned to 16-byte aligned</span></span>
<span id="cb24-48"><a href="#cb24-48" aria-hidden="true" tabindex="-1"></a>  fill_y<span class="op">(</span>y<span class="op">)</span>; <span class="co">// automatic conversion again</span></span>
<span id="cb24-49"><a href="#cb24-49" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb24-50"><a href="#cb24-50" aria-hidden="true" tabindex="-1"></a>  vectorized_axpy<span class="op">(</span>y, alpha, x<span class="op">)</span>;</span>
<span id="cb24-51"><a href="#cb24-51" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb24-52"><a href="#cb24-52" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="8" id="references"><span class="header-section-number">8</span> References<a href="#references" class="self-link"></a></h1>
<ul>
<li><p>Davis et al., “CheriABI: Enforcing Valid Pointer Provenance and
Minimizing Pointer Privilege in the POSIX C Run-time Environment,”
ASPLOS ’19, April 2019, pp. 379 - 393. Available online [last accessed
2024-07-05]:
<a href="https://dl.acm.org/doi/10.1145/3297858.3304042">https://dl.acm.org/doi/10.1145/3297858.3304042</a></p></li>
<li><p>Watson et al., “CHERI C/C++ Programming Guide,” Technical Report
UCAM-CL-TR-947, University of Cambridge Computer Laboratory, June 2020.
Available online [last accessed 2024-07-05]:
<a href="https://doi.org/10.48456/tr-947">https://doi.org/10.48456/tr-947</a></p></li>
</ul>
<h1 data-number="9" id="acknowledgments"><span class="header-section-number">9</span> Acknowledgments<a href="#acknowledgments" class="self-link"></a></h1>
<ul>
<li>For <code>detectably_invalid</code>, credit (with permission) to
David Sankel (Adobe), <code>dsankel@adobe.com</code></li>
</ul>
<h1 data-number="10" id="wording"><span class="header-section-number">10</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>
<p>In <em>[version.syn]</em>, add</p>
</blockquote>
<div class="sourceCode" id="cb25"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define __cpp_lib_aligned_accessor </span>YYYYMML<span class="pp"> </span><span class="co">// also in &lt;mdspan&gt;</span></span></code></pre></div>
<blockquote>
<p>Adjust the placeholder value as needed so as to denote this
proposal’s date of adoption.</p>
<p>To the Header <code>&lt;mdspan&gt;</code> synopsis
<strong>[mdspan.syn]</strong>, after <code>class default_accessor</code>
and before <code>class mdspan</code>, add the following.</p>
</blockquote>
<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="co">// [mdspan.accessor.aligned], class template aligned_accessor</span></span>
<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">class</span> aligned_accessor;</span></code></pre></div>
<blockquote>
<p>At the end of <strong>[mdspan.accessor.default]</strong> and before
<strong>[mdspan.mdspan]</strong>, add all the material that follows.</p>
</blockquote>
<h2 data-number="10.1" id="add-subsection-mdspan.accessor.aligned-with-the-following"><span class="header-section-number">10.1</span> Add subsection �
[mdspan.accessor.aligned] with the following<a href="#add-subsection-mdspan.accessor.aligned-with-the-following" class="self-link"></a></h2>
<p><b> � Class template <code>aligned_accessor</code>
[mdspan.accessor.aligned] </b></p>
<p><b> �.1 Overview [mdspan.accessor.aligned.overview] </b></p>
<div class="sourceCode" id="cb27"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> ElementType, <span class="dt">size_t</span> the_byte_alignment<span class="op">&gt;</span></span>
<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> aligned_accessor <span class="op">{</span></span>
<span id="cb27-3"><a href="#cb27-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="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb27-5"><a href="#cb27-5" 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="cb27-6"><a href="#cb27-6" 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="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-8"><a href="#cb27-8" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="kw">constexpr</span> <span class="dt">size_t</span> byte_alignment <span class="op">=</span> the_byte_alignment;</span>
<span id="cb27-9"><a href="#cb27-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-10"><a href="#cb27-10" 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="cb27-11"><a href="#cb27-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-12"><a href="#cb27-12" 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="cb27-13"><a href="#cb27-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb27-14"><a href="#cb27-14" 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="cb27-15"><a href="#cb27-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-16"><a href="#cb27-16" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb27-17"><a href="#cb27-17" aria-hidden="true" tabindex="-1"></a>    <span class="kw">explicit</span> <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb27-18"><a href="#cb27-18" aria-hidden="true" tabindex="-1"></a>      default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span>;</span>
<span id="cb27-19"><a href="#cb27-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-20"><a href="#cb27-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">operator</span> default_accessor<span class="op">&lt;</span>element_type<span class="op">&gt;()</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb27-21"><a href="#cb27-21" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb27-22"><a href="#cb27-22" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb27-23"><a href="#cb27-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-24"><a href="#cb27-24" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference 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>
<span id="cb27-25"><a href="#cb27-25" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-26"><a href="#cb27-26" 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="cb27-27"><a href="#cb27-27" 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>
<span id="cb27-28"><a href="#cb27-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb27-29"><a href="#cb27-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>data_handle_type p<span class="op">)</span>;</span>
<span id="cb27-30"><a href="#cb27-30" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Mandates</em>:</p>
<ul>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.1)</a></span>
<code>byte_alignment</code> is a power of two, and</p></li>
<li><p><span class="marginalizedparent"><a class="marginalized">(1.2)</a></span>
<code>byte_alignment &gt;= alignof(ElementType)</code> is
<code>true</code>.</p></li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<code>aligned_accessor</code> meets the accessor policy
requirements.</p>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<code>ElementType</code> is required to be a complete object type that
is neither an abstract class type nor an array type.</p>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
Each specialization of <code>aligned_accessor</code> is a trivially
copyable type that models <code>semiregular</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<span class="math inline">[0, <em>n</em>)</span> is an accessible range
for an object <code>p</code> of type <code>data_handle_type</code> and
an object of type <code>aligned_accessor</code> if and only if <span class="math inline">[</span><code>p</code>, <code>p</code> + <span class="math inline"><em>n</em>)</span> is a valid range.</p>
<h2 data-number="10.2" id="members-mdspan.accessor.aligned.members"><span class="header-section-number">10.2</span> Members
[mdspan.accessor.aligned.members]<a href="#members-mdspan.accessor.aligned.members" class="self-link"></a></h2>
<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="kw">class</span> OtherElementType, <span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb28-2"><a href="#cb28-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb28-3"><a href="#cb28-3" 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 class="op">{}</span></span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Constraints</em>:
<code>is_convertible_v&lt;OtherElementType(*)[], element_type(*)[]&gt;</code>
is <code>true</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Mandates</em>:
<code>gcd(other_byte_alignment, byte_alignment) == byte_alignment</code>
is <code>true</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">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb29-2"><a href="#cb29-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">explicit</span> <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb29-3"><a href="#cb29-3" aria-hidden="true" tabindex="-1"></a>    default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span> <span class="op">{}</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">3</a></span>
<em>Constraints</em>:
<code>is_convertible_v&lt;OtherElementType(*)[], element_type(*)[]&gt;</code>
is <code>true</code>.</p>
<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> reference 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></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">4</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>element_type</code>, where <code>X</code> has alignment
<code>byte_alignment</code> (<strong>[basic.align]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
<em>Effects</em>: Equivalent to:
<code>return assume_aligned&lt;byte_alignment&gt;(p)[i];</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> <span class="kw">typename</span> offset_policy<span class="op">::</span>data_handle_type</span>
<span id="cb31-2"><a href="#cb31-2" 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></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>element_type</code>, where <code>X</code> has alignment
<code>byte_alignment</code> (<strong>[basic.align]</strong>).</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects</em>: Equivalent to: <code>return p + i;</code></p>
<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">static</span> <span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>data_handle_type p<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>element_type</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns</em>: <code>true</code> if <code>X</code> has alignment at
least <code>byte_alignment</code>, else <code>false</code>.</p>
<p>[<em>Example:</em> The following function <code>compute</code> uses
<code>is_sufficiently_aligned</code> to check whether a given
<code>mdspan</code> with <code>default_accessor</code> has a data handle
with sufficient alignment to be used with
<code>aligned_accessor&lt;float, 4 * sizeof(float)&gt;</code>. If so,
the function dispatches to a function
<code>compute_using_fourfold_overalignment</code> that requires fourfold
overalignment of arrays, but can therefore use hardware-specific
instructions, such as four-wide SIMD (Single Instruction Multiple Data)
instructions. Otherwise, <code>compute</code> dispatches to a possibly
less optimized function
<code>compute_without_requiring_overalignment</code> that has no
overalignment requirement.</p>
<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">extern</span> <span class="dt">void</span></span>
<span id="cb33-2"><a href="#cb33-2" aria-hidden="true" tabindex="-1"></a>compute_using_fourfold_overalignment<span class="op">(</span></span>
<span id="cb33-3"><a href="#cb33-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right,</span>
<span id="cb33-4"><a href="#cb33-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">4</span> <span class="op">*</span> <span class="kw">alignof</span><span class="op">(</span><span class="dt">float</span><span class="op">)&gt;&gt;</span> x<span class="op">)</span>;</span>
<span id="cb33-5"><a href="#cb33-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-6"><a href="#cb33-6" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span></span>
<span id="cb33-7"><a href="#cb33-7" aria-hidden="true" tabindex="-1"></a>compute_without_requiring_overalignment<span class="op">(</span></span>
<span id="cb33-8"><a href="#cb33-8" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;</span> x<span class="op">)</span>;</span>
<span id="cb33-9"><a href="#cb33-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-10"><a href="#cb33-10" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> compute<span class="op">(</span>std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span><span class="op">&gt;&gt;</span> x<span class="op">)</span></span>
<span id="cb33-11"><a href="#cb33-11" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb33-12"><a href="#cb33-12" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> accessor <span class="op">=</span> aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, <span class="dv">4</span> <span class="op">*</span> <span class="kw">sizeof</span><span class="op">(</span><span class="dt">float</span><span class="op">)&gt;{}</span>;</span>
<span id="cb33-13"><a href="#cb33-13" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_handle <span class="op">=</span> x<span class="op">.</span>data_handle<span class="op">()</span>;</span>
<span id="cb33-14"><a href="#cb33-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb33-15"><a href="#cb33-15" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="op">(</span>accessor<span class="op">.</span>is_sufficiently_aligned<span class="op">(</span>x_handle<span class="op">))</span> <span class="op">{</span></span>
<span id="cb33-16"><a href="#cb33-16" aria-hidden="true" tabindex="-1"></a>    compute_using_fourfold_overalignment<span class="op">(</span>mdspan<span class="op">{</span>x_handle, x<span class="op">.</span>mapping<span class="op">()</span>, accessor<span class="op">})</span>;</span>
<span id="cb33-17"><a href="#cb33-17" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb33-18"><a href="#cb33-18" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb33-19"><a href="#cb33-19" aria-hidden="true" tabindex="-1"></a>    compute_without_requiring_overalignment<span class="op">(</span>x<span class="op">)</span>;</span>
<span id="cb33-20"><a href="#cb33-20" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb33-21"><a href="#cb33-21" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<p>[<em>Example:</em> The following example shows how users can fulfill
the preconditions of <code>aligned_accessor</code> by using existing C++
Standard Library functionality to create overaligned allocations. First,
the <code>allocate_overaligned</code> helper function uses
<code>aligned_alloc</code> to create an overaligned allocation.</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> ElementType<span class="op">&gt;</span></span>
<span id="cb34-2"><a href="#cb34-2" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_with_free <span class="op">{</span></span>
<span id="cb34-3"><a href="#cb34-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="cb34-4"><a href="#cb34-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="cb34-5"><a href="#cb34-5" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb34-6"><a href="#cb34-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb34-7"><a href="#cb34-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-8"><a href="#cb34-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="cb34-9"><a href="#cb34-9" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span> std<span class="op">::</span>unique_ptr<span class="op">&lt;</span>ElementType<span class="op">[]</span>, delete_with_free<span class="op">&lt;</span>ElementType<span class="op">&gt;&gt;</span>;</span>
<span id="cb34-10"><a href="#cb34-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb34-11"><a href="#cb34-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="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb34-12"><a href="#cb34-12" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span> allocate_overaligned<span class="op">(</span><span class="kw">const</span> <span class="dt">size_t</span> num_elements<span class="op">)</span></span>
<span id="cb34-13"><a href="#cb34-13" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb34-14"><a href="#cb34-14" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</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="cb34-15"><a href="#cb34-15" 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="cb34-16"><a href="#cb34-16" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="op">{</span>ptr, delete_with_free<span class="op">&lt;</span>ElementType<span class="op">&gt;{}}</span>;</span>
<span id="cb34-17"><a href="#cb34-17" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>Second, this example presumes that some third-party library provides
functions requiring arrays of <code>float</code> to have 32-byte
alignment.</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb35-1"><a href="#cb35-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb35-2"><a href="#cb35-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span> std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>,</span>
<span id="cb35-3"><a href="#cb35-3" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>layout_right, std<span class="op">::</span>aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb35-4"><a href="#cb35-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb35-5"><a href="#cb35-5" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">void</span> vectorized_axpy<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y, <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x<span class="op">)</span>;</span>
<span id="cb35-6"><a href="#cb35-6" aria-hidden="true" tabindex="-1"></a><span class="kw">extern</span> <span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</span>;</span></code></pre></div>
<p>Third and finally, the user’s function <code>user_function</code>
would begin by allocating “raw” overaligned arrays with
<code>allocate_overaligned</code>. It would then create aligned
<code>mdspan</code> with them, and pass the resulting
<code>mdspan</code> into the third-party library’s functions.</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="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha<span class="op">)</span></span>
<span id="cb36-2"><a href="#cb36-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb36-3"><a href="#cb36-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb36-4"><a href="#cb36-4" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span> allocate_overaligned<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb36-5"><a href="#cb36-5" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span> allocate_overaligned<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb36-6"><a href="#cb36-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-7"><a href="#cb36-7" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb36-8"><a href="#cb36-8" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">())</span>;</span>
<span id="cb36-9"><a href="#cb36-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-10"><a href="#cb36-10" aria-hidden="true" tabindex="-1"></a>  <span class="co">// ... fill the elements of x and y ...</span></span>
<span id="cb36-11"><a href="#cb36-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb36-12"><a href="#cb36-12" aria-hidden="true" tabindex="-1"></a>  vectorized_axpy<span class="op">(</span>y, alpha, x<span class="op">)</span>;</span>
<span id="cb36-13"><a href="#cb36-13" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb36-14"><a href="#cb36-14" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p>–<em>end example</em>]</p>
<h1 data-number="11" id="wording-for-alternative-nonmember-is_sufficiently_aligned-design"><span class="header-section-number">11</span> Wording for alternative
nonmember <code>is_sufficiently_aligned</code> design<a href="#wording-for-alternative-nonmember-is_sufficiently_aligned-design" class="self-link"></a></h1>
<blockquote>
<p>Text in blockquotes is not proposed wording, but rather instructions
for generating proposed wording. The instructions here are expressed as
a “diff” atop P2897R2, that is, as if the wording proposed in P2897R2
had already been applied to the Working Draft. The � character is used
to denote a placeholder section number which the editor shall
determine.</p>
</blockquote>
<blockquote>
<p>From the <code>aligned_accessor</code> synopsis in
<strong>[mdspan.accessor.aligned.overview]</strong>, remove the member
function
<code>static bool is_sufficiently_aligned(data_handle_type p);</code>.</p>
</blockquote>
<blockquote>
<p>From the list of members of <code>aligned_accessor</code> in
<strong>[mdspan.accessor.aligned.members]</strong>, remove
<code>static bool is_sufficiently_aligned(data_handle_type p);</code>
from after line 7 (“<em>Effects</em>: Equivalent to:
<code>return p + i;</code>”), and remove line 8
(“<em>Preconditions</em>: …”) and line 9 (“<em>Returns</em>: …”).
(Retain the <em>Example</em> using <code>is_sufficiently_aligned</code>
that immediately follows the deleted lines.)</p>
</blockquote>
<blockquote>
<p>To the Header <code>&lt;bit&gt;</code> synopsis
<strong>[bit.syn]</strong>, after <code>enum class endian</code> and
before the <code>}</code> that closes <code>namespace std</code>, add
the following.</p>
</blockquote>
<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="co">// [bit.aligned], is_sufficiently_aligned</span></span>
<span id="cb37-2"><a href="#cb37-2" 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="cb37-3"><a href="#cb37-3" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>ElementType<span class="op">*)</span>;</span></code></pre></div>
<blockquote>
<p>After <strong>[bit.endian]</strong>, add a new section
<strong>[bit.aligned]</strong> and put in it all the material that
follows.</p>
</blockquote>
<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">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="cb38-2"><a href="#cb38-2" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> is_sufficiently_aligned<span class="op">(</span>ElementType<span class="op">*</span> p<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">1</a></span>
<em>Preconditions</em>: <code>p</code> points to an object
<code>X</code> of a type similar (<strong>[conv.qual]</strong>) to
<code>ElementType</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">2</a></span>
<em>Returns</em>: <code>true</code> if <code>X</code> has alignment at
least <code>byte_alignment</code>, else <code>false</code>.</p>
<h1 data-number="12" id="appendix-a-detectably_invalid-nonmember-function-example"><span class="header-section-number">12</span> Appendix A:
<code>detectably_invalid</code> nonmember function example<a href="#appendix-a-detectably_invalid-nonmember-function-example" class="self-link"></a></h1>
<p>This section is nonnormative. This is the full source code with tests
for the <code>detectably_invalid</code> nonmember function example
above. Please see this
<a href="https://godbolt.org/z/4P9MGbhdj">Compiler Explorer link</a> for
a test with five different compilers: GCC 14.1, Clang 18.1.0, MSVC
v19.40 (VS17.10), and nvc++ 24.5.</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb39-1"><a href="#cb39-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb39-2"><a href="#cb39-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;concepts&gt;</span></span>
<span id="cb39-3"><a href="#cb39-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cstdint&gt;</span></span>
<span id="cb39-4"><a href="#cb39-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;iostream&gt;</span></span>
<span id="cb39-5"><a href="#cb39-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;stdexcept&gt;</span></span>
<span id="cb39-6"><a href="#cb39-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb39-7"><a href="#cb39-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;utility&gt;</span></span>
<span id="cb39-8"><a href="#cb39-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-9"><a href="#cb39-9" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb39-10"><a href="#cb39-10" aria-hidden="true" tabindex="-1"></a><span class="kw">concept</span> has_detectably_invalid <span class="op">=</span> <span class="kw">requires</span><span class="op">(</span>Accessor acc<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-11"><a href="#cb39-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type;</span>
<span id="cb39-12"><a href="#cb39-12" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span> std<span class="op">::</span>as_const<span class="op">(</span>acc<span class="op">).</span>detectably_invalid<span class="op">(</span></span>
<span id="cb39-13"><a href="#cb39-13" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span><span class="kw">typename</span> Accessor<span class="op">::</span>data_handle_type<span class="op">&gt;()</span>,</span>
<span id="cb39-14"><a href="#cb39-14" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>declval<span class="op">&lt;</span>std<span class="op">::</span><span class="dt">size_t</span><span class="op">&gt;()</span></span>
<span id="cb39-15"><a href="#cb39-15" aria-hidden="true" tabindex="-1"></a>    <span class="op">)</span> <span class="op">}</span> <span class="kw">noexcept</span> <span class="op">-&gt;</span> std<span class="op">::</span>convertible_to<span class="op">&lt;</span><span class="dt">bool</span><span class="op">&gt;</span>;</span>
<span id="cb39-16"><a href="#cb39-16" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-17"><a href="#cb39-17" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-18"><a href="#cb39-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> Accessor<span class="op">&gt;</span></span>
<span id="cb39-19"><a href="#cb39-19" aria-hidden="true" tabindex="-1"></a><span class="dt">bool</span> detectably_invalid<span class="op">(</span>Accessor<span class="op">&amp;&amp;</span> accessor,</span>
<span id="cb39-20"><a href="#cb39-20" aria-hidden="true" tabindex="-1"></a>  <span class="kw">typename</span> std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;::</span>data_handle_type handle,</span>
<span id="cb39-21"><a href="#cb39-21" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span></span>
<span id="cb39-22"><a href="#cb39-22" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb39-23"><a href="#cb39-23" aria-hidden="true" tabindex="-1"></a>  <span class="cf">if</span> <span class="kw">constexpr</span> <span class="op">(</span>has_detectably_invalid<span class="op">&lt;</span>std<span class="op">::</span>remove_cvref_t<span class="op">&lt;</span>Accessor<span class="op">&gt;&gt;)</span> <span class="op">{</span></span>
<span id="cb39-24"><a href="#cb39-24" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> std<span class="op">::</span>as_const<span class="op">(</span>accessor<span class="op">).</span>detectably_invalid<span class="op">(</span>handle, size<span class="op">)</span>;</span>
<span id="cb39-25"><a href="#cb39-25" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-26"><a href="#cb39-26" aria-hidden="true" tabindex="-1"></a>  <span class="cf">else</span> <span class="op">{</span></span>
<span id="cb39-27"><a href="#cb39-27" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">false</span>;</span>
<span id="cb39-28"><a href="#cb39-28" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-29"><a href="#cb39-29" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb39-30"><a href="#cb39-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-31"><a href="#cb39-31" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> A <span class="op">{</span></span>
<span id="cb39-32"><a href="#cb39-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-33"><a href="#cb39-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-34"><a href="#cb39-34" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">noexcept</span> <span class="op">{</span></span>
<span id="cb39-35"><a href="#cb39-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> ptr <span class="op">==</span> <span class="kw">nullptr</span> <span class="op">&amp;&amp;</span> size <span class="op">!=</span> <span class="dv">0</span>;</span>
<span id="cb39-36"><a href="#cb39-36" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-37"><a href="#cb39-37" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-38"><a href="#cb39-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-39"><a href="#cb39-39" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> B <span class="op">{</span></span>
<span id="cb39-40"><a href="#cb39-40" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-41"><a href="#cb39-41" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-42"><a href="#cb39-42" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-43"><a href="#cb39-43" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> C <span class="op">{</span></span>
<span id="cb39-44"><a href="#cb39-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-45"><a href="#cb39-45" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-46"><a href="#cb39-46" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This is nonconst, so it&#39;s not actually called.</span></span>
<span id="cb39-47"><a href="#cb39-47" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-48"><a href="#cb39-48" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>runtime_error<span class="op">(</span><span class="st">&quot;C::detectably_invalid: uh oh&quot;</span><span class="op">)</span>;</span>
<span id="cb39-49"><a href="#cb39-49" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-50"><a href="#cb39-50" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-51"><a href="#cb39-51" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-52"><a href="#cb39-52" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> D <span class="op">{</span></span>
<span id="cb39-53"><a href="#cb39-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> data_handle_type <span class="op">=</span> <span class="dt">float</span><span class="op">*</span>;</span>
<span id="cb39-54"><a href="#cb39-54" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-55"><a href="#cb39-55" aria-hidden="true" tabindex="-1"></a>  <span class="co">// This is const but not noexcept, so it&#39;s not actually called.</span></span>
<span id="cb39-56"><a href="#cb39-56" aria-hidden="true" tabindex="-1"></a>  <span class="dt">bool</span> detectably_invalid<span class="op">(</span>data_handle_type ptr, std<span class="op">::</span><span class="dt">size_t</span> size<span class="op">)</span> <span class="kw">const</span> <span class="op">{</span></span>
<span id="cb39-57"><a href="#cb39-57" aria-hidden="true" tabindex="-1"></a>    <span class="cf">throw</span> std<span class="op">::</span>runtime_error<span class="op">(</span><span class="st">&quot;D::detectably_invalid: uh oh&quot;</span><span class="op">)</span>;</span>
<span id="cb39-58"><a href="#cb39-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-59"><a href="#cb39-59" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb39-60"><a href="#cb39-60" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-61"><a href="#cb39-61" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-62"><a href="#cb39-62" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">()</span></span>
<span id="cb39-63"><a href="#cb39-63" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb39-64"><a href="#cb39-64" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span><span class="op">*</span> ptr <span class="op">=</span> <span class="kw">nullptr</span>;</span>
<span id="cb39-65"><a href="#cb39-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-66"><a href="#cb39-66" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>A<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-67"><a href="#cb39-67" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>A<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-68"><a href="#cb39-68" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-69"><a href="#cb39-69" aria-hidden="true" tabindex="-1"></a>  A a<span class="op">{}</span>;</span>
<span id="cb39-70"><a href="#cb39-70" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>a, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-71"><a href="#cb39-71" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>a, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-72"><a href="#cb39-72" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-73"><a href="#cb39-73" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> A a_c<span class="op">{}</span>;</span>
<span id="cb39-74"><a href="#cb39-74" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>a_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-75"><a href="#cb39-75" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>detectably_invalid<span class="op">(</span>a_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-76"><a href="#cb39-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-77"><a href="#cb39-77" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-78"><a href="#cb39-78" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-79"><a href="#cb39-79" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-80"><a href="#cb39-80" aria-hidden="true" tabindex="-1"></a>  <span class="co">// B doesn&#39;t know how to check pointer validity.</span></span>
<span id="cb39-81"><a href="#cb39-81" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-82"><a href="#cb39-82" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-83"><a href="#cb39-83" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>B<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-84"><a href="#cb39-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-85"><a href="#cb39-85" aria-hidden="true" tabindex="-1"></a>  B b<span class="op">{}</span>;</span>
<span id="cb39-86"><a href="#cb39-86" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-87"><a href="#cb39-87" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-88"><a href="#cb39-88" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-89"><a href="#cb39-89" aria-hidden="true" tabindex="-1"></a>  <span class="kw">const</span> B b_c<span class="op">{}</span>;</span>
<span id="cb39-90"><a href="#cb39-90" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-91"><a href="#cb39-91" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>b_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-92"><a href="#cb39-92" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-93"><a href="#cb39-93" aria-hidden="true" tabindex="-1"></a>  <span class="co">// If users make detectably_invalid nonconst or not noexcept,</span></span>
<span id="cb39-94"><a href="#cb39-94" aria-hidden="true" tabindex="-1"></a>  <span class="co">// the nonmember function falls back to a default implementation.</span></span>
<span id="cb39-95"><a href="#cb39-95" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-96"><a href="#cb39-96" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-97"><a href="#cb39-97" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>C<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-98"><a href="#cb39-98" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>C<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-99"><a href="#cb39-99" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-100"><a href="#cb39-100" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-101"><a href="#cb39-101" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;C{} threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-102"><a href="#cb39-102" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-103"><a href="#cb39-103" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-104"><a href="#cb39-104" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-105"><a href="#cb39-105" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> C c_c<span class="op">{}</span>;</span>
<span id="cb39-106"><a href="#cb39-106" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-107"><a href="#cb39-107" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-108"><a href="#cb39-108" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-109"><a href="#cb39-109" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-110"><a href="#cb39-110" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;const C threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-111"><a href="#cb39-111" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-112"><a href="#cb39-112" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-113"><a href="#cb39-113" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-114"><a href="#cb39-114" aria-hidden="true" tabindex="-1"></a>    C c<span class="op">{}</span>;</span>
<span id="cb39-115"><a href="#cb39-115" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-116"><a href="#cb39-116" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-117"><a href="#cb39-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-118"><a href="#cb39-118" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-119"><a href="#cb39-119" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;nonconst C threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-120"><a href="#cb39-120" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-121"><a href="#cb39-121" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-122"><a href="#cb39-122" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-123"><a href="#cb39-123" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>D<span class="op">{}</span>, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-124"><a href="#cb39-124" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>D<span class="op">{}</span>, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-125"><a href="#cb39-125" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-126"><a href="#cb39-126" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-127"><a href="#cb39-127" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;D{} threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-128"><a href="#cb39-128" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-129"><a href="#cb39-129" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-130"><a href="#cb39-130" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-131"><a href="#cb39-131" aria-hidden="true" tabindex="-1"></a>    <span class="kw">const</span> D d_c<span class="op">{}</span>;</span>
<span id="cb39-132"><a href="#cb39-132" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d_c, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-133"><a href="#cb39-133" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d_c, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-134"><a href="#cb39-134" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-135"><a href="#cb39-135" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-136"><a href="#cb39-136" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;const D threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-137"><a href="#cb39-137" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-138"><a href="#cb39-138" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-139"><a href="#cb39-139" aria-hidden="true" tabindex="-1"></a>  <span class="cf">try</span> <span class="op">{</span></span>
<span id="cb39-140"><a href="#cb39-140" aria-hidden="true" tabindex="-1"></a>    D d<span class="op">{}</span>;</span>
<span id="cb39-141"><a href="#cb39-141" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d, ptr, <span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb39-142"><a href="#cb39-142" aria-hidden="true" tabindex="-1"></a>    <span class="ot">assert</span><span class="op">(</span><span class="kw">not</span> detectably_invalid<span class="op">(</span>d, ptr, <span class="dv">1</span><span class="op">))</span>;</span>
<span id="cb39-143"><a href="#cb39-143" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-144"><a href="#cb39-144" aria-hidden="true" tabindex="-1"></a>  <span class="cf">catch</span> <span class="op">(</span><span class="kw">const</span> std<span class="op">::</span>runtime_error<span class="op">&amp;</span> e<span class="op">)</span> <span class="op">{</span></span>
<span id="cb39-145"><a href="#cb39-145" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;nonconst D threw runtime_error: &quot;</span> <span class="op">&lt;&lt;</span> e<span class="op">.</span>what<span class="op">()</span> <span class="op">&lt;&lt;</span> <span class="st">&quot;</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-146"><a href="#cb39-146" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb39-147"><a href="#cb39-147" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb39-148"><a href="#cb39-148" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>cerr <span class="op">&lt;&lt;</span> <span class="st">&quot;Made it to the end</span><span class="sc">\n</span><span class="st">&quot;</span>;</span>
<span id="cb39-149"><a href="#cb39-149" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb39-150"><a href="#cb39-150" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<h1 data-number="13" id="appendix-b-implementation-and-demo"><span class="header-section-number">13</span> Appendix B: Implementation and
demo<a href="#appendix-b-implementation-and-demo" class="self-link"></a></h1>
<p><a href="https://godbolt.org/z/hjqExKaeh">This Compiler Explorer
link</a> gives a full implementation of <code>aligned_accessor</code>
and a demonstration. We show the full source code from that link here
below.</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="pp">#include </span><span class="im">&lt;https://raw.githubusercontent.com/kokkos/mdspan/single-header/mdspan.hpp&gt;</span></span>
<span id="cb40-2"><a href="#cb40-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;bit&gt;</span></span>
<span id="cb40-3"><a href="#cb40-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cassert&gt;</span></span>
<span id="cb40-4"><a href="#cb40-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;cmath&gt;</span></span>
<span id="cb40-5"><a href="#cb40-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(_MSC_VER)</span></span>
<span id="cb40-6"><a href="#cb40-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#  include </span><span class="im">&lt;cstdlib&gt;</span><span class="pp"> </span><span class="co">// MSVC&#39;s _aligned_malloc</span></span>
<span id="cb40-7"><a href="#cb40-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb40-8"><a href="#cb40-8" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;exception&gt;</span></span>
<span id="cb40-9"><a href="#cb40-9" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;functional&gt;</span></span>
<span id="cb40-10"><a href="#cb40-10" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;memory&gt;</span></span>
<span id="cb40-11"><a href="#cb40-11" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;numeric&gt;</span></span>
<span id="cb40-12"><a href="#cb40-12" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">&lt;type_traits&gt;</span></span>
<span id="cb40-13"><a href="#cb40-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-14"><a href="#cb40-14" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> stdex <span class="op">=</span> std<span class="op">::</span>experimental;</span>
<span id="cb40-15"><a href="#cb40-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-16"><a href="#cb40-16" aria-hidden="true" tabindex="-1"></a><span class="co">// P2389 (voted into C++ at June 2024 STL plenary)</span></span>
<span id="cb40-17"><a href="#cb40-17" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> std <span class="op">{</span></span>
<span id="cb40-18"><a href="#cb40-18" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> Rank, <span class="kw">class</span> IndexType <span class="op">=</span> <span class="dt">size_t</span><span class="op">&gt;</span></span>
<span id="cb40-19"><a href="#cb40-19" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> dims <span class="op">=</span> dextents<span class="op">&lt;</span>IndexType, Rank<span class="op">&gt;</span>;</span>
<span id="cb40-20"><a href="#cb40-20" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace std</span></span>
<span id="cb40-21"><a href="#cb40-21" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-22"><a href="#cb40-22" aria-hidden="true" tabindex="-1"></a><span class="kw">namespace</span> <span class="op">{</span></span>
<span id="cb40-23"><a href="#cb40-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-24"><a href="#cb40-24" 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="cb40-25"><a href="#cb40-25" aria-hidden="true" tabindex="-1"></a><span class="kw">class</span> aligned_accessor <span class="op">{</span></span>
<span id="cb40-26"><a href="#cb40-26" aria-hidden="true" tabindex="-1"></a><span class="kw">public</span><span class="op">:</span></span>
<span id="cb40-27"><a href="#cb40-27" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>std<span class="op">::</span>has_single_bit<span class="op">(</span>byte_alignment<span class="op">)</span>,</span>
<span id="cb40-28"><a href="#cb40-28" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;byte_alignment must be a power of two.&quot;</span><span class="op">)</span>;</span>
<span id="cb40-29"><a href="#cb40-29" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static_assert</span><span class="op">(</span>byte_alignment <span class="op">&gt;=</span> <span class="kw">alignof</span><span class="op">(</span>ElementType<span class="op">)</span>,</span>
<span id="cb40-30"><a href="#cb40-30" aria-hidden="true" tabindex="-1"></a>    <span class="st">&quot;Insufficient byte alignment for ElementType&quot;</span><span class="op">)</span>;</span>
<span id="cb40-31"><a href="#cb40-31" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-32"><a href="#cb40-32" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> offset_policy <span class="op">=</span> stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>ElementType<span class="op">&gt;</span>;</span>
<span id="cb40-33"><a href="#cb40-33" aria-hidden="true" tabindex="-1"></a>  <span class="kw">using</span> element_type <span class="op">=</span> ElementType;</span>
<span id="cb40-34"><a href="#cb40-34" 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="cb40-35"><a href="#cb40-35" 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="cb40-36"><a href="#cb40-36" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-37"><a href="#cb40-37" 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="cb40-38"><a href="#cb40-38" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-39"><a href="#cb40-39" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span></span>
<span id="cb40-40"><a href="#cb40-40" aria-hidden="true" tabindex="-1"></a>    <span class="kw">class</span> OtherElementType,</span>
<span id="cb40-41"><a href="#cb40-41" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span><span class="dt">size_t</span> other_byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-42"><a href="#cb40-42" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span>std<span class="op">::</span>is_convertible_v<span class="op">&lt;</span></span>
<span id="cb40-43"><a href="#cb40-43" aria-hidden="true" tabindex="-1"></a>    OtherElementType<span class="op">(*)[]</span>, element_type<span class="op">(*)[]&gt;)</span></span>
<span id="cb40-44"><a href="#cb40-44" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> aligned_accessor<span class="op">(</span></span>
<span id="cb40-45"><a href="#cb40-45" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span>OtherElementType, other_byte_alignment<span class="op">&gt;)</span></span>
<span id="cb40-46"><a href="#cb40-46" aria-hidden="true" tabindex="-1"></a>      <span class="kw">noexcept</span></span>
<span id="cb40-47"><a href="#cb40-47" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-48"><a href="#cb40-48" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> <span class="dt">size_t</span> the_gcd <span class="op">=</span></span>
<span id="cb40-49"><a href="#cb40-49" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>gcd<span class="op">(</span>other_byte_alignment, byte_alignment<span class="op">)</span>;</span>
<span id="cb40-50"><a href="#cb40-50" aria-hidden="true" tabindex="-1"></a>    <span class="kw">static_assert</span><span class="op">(</span>the_gcd <span class="op">==</span> byte_alignment<span class="op">)</span>;</span>
<span id="cb40-51"><a href="#cb40-51" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-52"><a href="#cb40-52" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-53"><a href="#cb40-53" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span><span class="kw">class</span> OtherElementType<span class="op">&gt;</span></span>
<span id="cb40-54"><a href="#cb40-54" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span><span class="op">(</span>std<span class="op">::</span>is_convertible_v<span class="op">&lt;</span></span>
<span id="cb40-55"><a href="#cb40-55" aria-hidden="true" tabindex="-1"></a>    OtherElementType<span class="op">(*)[]</span>, element_type<span class="op">(*)[]&gt;)</span></span>
<span id="cb40-56"><a href="#cb40-56" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="kw">explicit</span> aligned_accessor<span class="op">(</span></span>
<span id="cb40-57"><a href="#cb40-57" aria-hidden="true" tabindex="-1"></a>    stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>OtherElementType<span class="op">&gt;)</span> <span class="kw">noexcept</span></span>
<span id="cb40-58"><a href="#cb40-58" aria-hidden="true" tabindex="-1"></a>  <span class="op">{}</span></span>
<span id="cb40-59"><a href="#cb40-59" aria-hidden="true" tabindex="-1"></a> </span>
<span id="cb40-60"><a href="#cb40-60" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span></span>
<span id="cb40-61"><a href="#cb40-61" aria-hidden="true" tabindex="-1"></a>    <span class="kw">operator</span> stdex<span class="op">::</span>default_accessor<span class="op">&lt;</span>element_type<span class="op">&gt;()</span> <span class="kw">const</span></span>
<span id="cb40-62"><a href="#cb40-62" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-63"><a href="#cb40-63" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="op">{}</span>;</span>
<span id="cb40-64"><a href="#cb40-64" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-65"><a href="#cb40-65" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-66"><a href="#cb40-66" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> reference</span>
<span id="cb40-67"><a href="#cb40-67" 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>
<span id="cb40-68"><a href="#cb40-68" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-69"><a href="#cb40-69" 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="cb40-70"><a href="#cb40-70" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-71"><a href="#cb40-71" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-72"><a href="#cb40-72" 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="cb40-73"><a href="#cb40-73" 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="cb40-74"><a href="#cb40-74" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> p <span class="op">+</span> i;</span>
<span id="cb40-75"><a href="#cb40-75" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-76"><a href="#cb40-76" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-77"><a href="#cb40-77" aria-hidden="true" tabindex="-1"></a>  <span class="kw">static</span> <span class="dt">bool</span></span>
<span id="cb40-78"><a href="#cb40-78" aria-hidden="true" tabindex="-1"></a>    is_sufficiently_aligned<span class="op">(</span>data_handle_type p<span class="op">)</span> <span class="kw">noexcept</span></span>
<span id="cb40-79"><a href="#cb40-79" aria-hidden="true" tabindex="-1"></a>  <span class="op">{</span></span>
<span id="cb40-80"><a href="#cb40-80" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="kw">alignof</span><span class="op">(</span>ElementType<span class="op">)</span> <span class="op">&gt;=</span> byte_alignment <span class="op">&amp;&amp;</span> </span>
<span id="cb40-81"><a href="#cb40-81" aria-hidden="true" tabindex="-1"></a>      std<span class="op">::</span>bit_cast<span class="op">&lt;</span><span class="dt">uintptr_t</span><span class="op">&gt;(</span>p<span class="op">)</span> <span class="op">%</span> byte_alignment <span class="op">==</span> <span class="dv">0</span>;</span>
<span id="cb40-82"><a href="#cb40-82" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-83"><a href="#cb40-83" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb40-84"><a href="#cb40-84" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-85"><a href="#cb40-85" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><span class="dt">size_t</span> byte_alignment<span class="op">&gt;</span></span>
<span id="cb40-86"><a href="#cb40-86" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> aligned_mdspan <span class="op">=</span></span>
<span id="cb40-87"><a href="#cb40-87" aria-hidden="true" tabindex="-1"></a>  std<span class="op">::</span>mdspan<span class="op">&lt;</span><span class="dt">float</span>, std<span class="op">::</span>dims<span class="op">&lt;</span><span class="dv">1</span>, <span class="dt">int</span><span class="op">&gt;</span>, std<span class="op">::</span>layout_right,</span>
<span id="cb40-88"><a href="#cb40-88" aria-hidden="true" tabindex="-1"></a>    aligned_accessor<span class="op">&lt;</span><span class="dt">float</span>, byte_alignment<span class="op">&gt;&gt;</span>;</span>
<span id="cb40-89"><a href="#cb40-89" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-90"><a href="#cb40-90" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 32-byte alignment,</span></span>
<span id="cb40-91"><a href="#cb40-91" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 8-wide SIMD of float.</span></span>
<span id="cb40-92"><a href="#cb40-92" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span></span>
<span id="cb40-93"><a href="#cb40-93" aria-hidden="true" tabindex="-1"></a>vectorized_axpby<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y,</span>
<span id="cb40-94"><a href="#cb40-94" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> alpha, aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> x, <span class="dt">float</span> beta<span class="op">)</span></span>
<span id="cb40-95"><a href="#cb40-95" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-96"><a href="#cb40-96" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span> <span class="op">==</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">))</span>;</span>
<span id="cb40-97"><a href="#cb40-97" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-98"><a href="#cb40-98" aria-hidden="true" tabindex="-1"></a>    y<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> beta <span class="op">*</span> y<span class="op">[</span>k<span class="op">]</span> <span class="op">+</span> alpha <span class="op">*</span> x<span class="op">[</span>k<span class="op">]</span>; </span>
<span id="cb40-99"><a href="#cb40-99" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-100"><a href="#cb40-100" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-101"><a href="#cb40-101" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-102"><a href="#cb40-102" aria-hidden="true" tabindex="-1"></a><span class="co">// 1-norm of the vector y</span></span>
<span id="cb40-103"><a href="#cb40-103" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> vectorized_norm<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">32</span><span class="op">&gt;</span> y<span class="op">)</span></span>
<span id="cb40-104"><a href="#cb40-104" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-105"><a href="#cb40-105" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> one_norm <span class="op">=</span> <span class="fl">0.0</span><span class="bu">f</span>;</span>
<span id="cb40-106"><a href="#cb40-106" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-107"><a href="#cb40-107" aria-hidden="true" tabindex="-1"></a>    one_norm <span class="op">+=</span> std<span class="op">::</span>fabs<span class="op">(</span>y<span class="op">[</span>k<span class="op">])</span>; </span>
<span id="cb40-108"><a href="#cb40-108" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-109"><a href="#cb40-109" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> one_norm;</span>
<span id="cb40-110"><a href="#cb40-110" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-111"><a href="#cb40-111" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-112"><a href="#cb40-112" aria-hidden="true" tabindex="-1"></a><span class="co">// Interfaces that require 16-byte alignment,</span></span>
<span id="cb40-113"><a href="#cb40-113" aria-hidden="true" tabindex="-1"></a><span class="co">// because they want to do 4-wide SIMD of float.</span></span>
<span id="cb40-114"><a href="#cb40-114" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fill_x<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> x<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-115"><a href="#cb40-115" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> x<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-116"><a href="#cb40-116" aria-hidden="true" tabindex="-1"></a>    x<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>k <span class="op">+</span> <span class="dv">2</span><span class="op">)</span>;</span>
<span id="cb40-117"><a href="#cb40-117" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>  </span>
<span id="cb40-118"><a href="#cb40-118" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-119"><a href="#cb40-119" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> fill_y<span class="op">(</span>aligned_mdspan<span class="op">&lt;</span><span class="dv">16</span><span class="op">&gt;</span> y<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-120"><a href="#cb40-120" aria-hidden="true" tabindex="-1"></a>  <span class="cf">for</span> <span class="op">(</span><span class="dt">int</span> k <span class="op">=</span> <span class="dv">0</span>; k <span class="op">&lt;</span> y<span class="op">.</span>extent<span class="op">(</span><span class="dv">0</span><span class="op">)</span>; <span class="op">++</span>k<span class="op">)</span> <span class="op">{</span></span>
<span id="cb40-121"><a href="#cb40-121" aria-hidden="true" tabindex="-1"></a>    y<span class="op">[</span>k<span class="op">]</span> <span class="op">=</span> <span class="kw">static_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">&gt;(</span>k <span class="op">-</span> <span class="dv">1</span><span class="op">)</span>;</span>
<span id="cb40-122"><a href="#cb40-122" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span>  </span>
<span id="cb40-123"><a href="#cb40-123" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-124"><a href="#cb40-124" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-125"><a href="#cb40-125" aria-hidden="true" tabindex="-1"></a><span class="co">// Helper functions for making overaligned array allocations.</span></span>
<span id="cb40-126"><a href="#cb40-126" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-127"><a href="#cb40-127" 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="cb40-128"><a href="#cb40-128" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> delete_raw <span class="op">{</span></span>
<span id="cb40-129"><a href="#cb40-129" 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="cb40-130"><a href="#cb40-130" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>free<span class="op">(</span>p<span class="op">)</span>;</span>
<span id="cb40-131"><a href="#cb40-131" aria-hidden="true" tabindex="-1"></a>  <span class="op">}</span></span>
<span id="cb40-132"><a href="#cb40-132" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb40-133"><a href="#cb40-133" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-134"><a href="#cb40-134" 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="cb40-135"><a href="#cb40-135" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> allocation <span class="op">=</span></span>
<span id="cb40-136"><a href="#cb40-136" 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="cb40-137"><a href="#cb40-137" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-138"><a href="#cb40-138" 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="cb40-139"><a href="#cb40-139" aria-hidden="true" tabindex="-1"></a>allocation<span class="op">&lt;</span>ElementType<span class="op">&gt;</span> 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="cb40-140"><a href="#cb40-140" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-141"><a href="#cb40-141" 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="cb40-142"><a href="#cb40-142" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span><span class="op">*</span> ptr <span class="op">=</span> <span class="kw">reinterpret_cast</span><span class="op">&lt;</span><span class="dt">float</span><span class="op">*&gt;(</span></span>
<span id="cb40-143"><a href="#cb40-143" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(_MSC_VER)</span></span>
<span id="cb40-144"><a href="#cb40-144" aria-hidden="true" tabindex="-1"></a>    _aligned_malloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span></span>
<span id="cb40-145"><a href="#cb40-145" aria-hidden="true" tabindex="-1"></a><span class="pp">#else</span></span>
<span id="cb40-146"><a href="#cb40-146" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>aligned_alloc<span class="op">(</span>byte_alignment, num_bytes<span class="op">)</span></span>
<span id="cb40-147"><a href="#cb40-147" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb40-148"><a href="#cb40-148" aria-hidden="true" tabindex="-1"></a>  <span class="op">)</span>;</span>
<span id="cb40-149"><a href="#cb40-149" 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="cb40-150"><a href="#cb40-150" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-151"><a href="#cb40-151" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-152"><a href="#cb40-152" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> user_function<span class="op">(</span><span class="dt">size_t</span> num_elements, <span class="dt">float</span> alpha, <span class="dt">float</span> beta<span class="op">)</span></span>
<span id="cb40-153"><a href="#cb40-153" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-154"><a href="#cb40-154" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> <span class="dt">size_t</span> max_byte_alignment <span class="op">=</span> <span class="dv">32</span>;</span>
<span id="cb40-155"><a href="#cb40-155" aria-hidden="true" tabindex="-1"></a>  <span class="co">// unique_ptr&lt;float[], deleter_something&gt;</span></span>
<span id="cb40-156"><a href="#cb40-156" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> x_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb40-157"><a href="#cb40-157" aria-hidden="true" tabindex="-1"></a>  <span class="kw">auto</span> y_alloc <span class="op">=</span> allocate_raw<span class="op">&lt;</span><span class="dt">float</span>, max_byte_alignment<span class="op">&gt;(</span>num_elements<span class="op">)</span>;</span>
<span id="cb40-158"><a href="#cb40-158" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-159"><a href="#cb40-159" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> x<span class="op">(</span>x_alloc<span class="op">.</span>get<span class="op">()</span>, num_elements<span class="op">)</span>;</span>
<span id="cb40-160"><a href="#cb40-160" aria-hidden="true" tabindex="-1"></a>  aligned_mdspan<span class="op">&lt;</span>max_byte_alignment<span class="op">&gt;</span> y<span class="op">(</span>y_alloc<span class="op">.</span>get<span class="op">()</span>, num_elements<span class="op">)</span>;</span>
<span id="cb40-161"><a href="#cb40-161" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-162"><a href="#cb40-162" aria-hidden="true" tabindex="-1"></a>  <span class="co">// expect aligned_mdspan&lt;16&gt;, get aligned_mdspan&lt;32&gt;</span></span>
<span id="cb40-163"><a href="#cb40-163" aria-hidden="true" tabindex="-1"></a>  fill_x<span class="op">(</span>x<span class="op">)</span>; <span class="co">// automatic conversion from 32-byte aligned to 16-byte aligned</span></span>
<span id="cb40-164"><a href="#cb40-164" aria-hidden="true" tabindex="-1"></a>  fill_y<span class="op">(</span>y<span class="op">)</span>; <span class="co">// automatic conversion again</span></span>
<span id="cb40-165"><a href="#cb40-165" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-166"><a href="#cb40-166" aria-hidden="true" tabindex="-1"></a>  <span class="co">// expect aligned_mdspan&lt;32&gt;, get aligned_mdspan&lt;32&gt;</span></span>
<span id="cb40-167"><a href="#cb40-167" aria-hidden="true" tabindex="-1"></a>  vectorized_axpby<span class="op">(</span>y, alpha, x, beta<span class="op">)</span>;</span>
<span id="cb40-168"><a href="#cb40-168" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> vectorized_norm<span class="op">(</span>y<span class="op">)</span>;</span>
<span id="cb40-169"><a href="#cb40-169" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb40-170"><a href="#cb40-170" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-171"><a href="#cb40-171" aria-hidden="true" tabindex="-1"></a><span class="op">}</span> <span class="co">// namespace (anonymous)</span></span>
<span id="cb40-172"><a href="#cb40-172" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb40-173"><a href="#cb40-173" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> main<span class="op">(</span><span class="dt">int</span> argc, <span class="dt">char</span><span class="op">*</span> argv<span class="op">[])</span></span>
<span id="cb40-174"><a href="#cb40-174" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb40-175"><a href="#cb40-175" aria-hidden="true" tabindex="-1"></a>  <span class="dt">float</span> result <span class="op">=</span> user_function<span class="op">(</span><span class="dv">10</span>, <span class="fl">1.0</span><span class="bu">f</span>, <span class="op">-</span><span class="fl">1.0</span><span class="bu">f</span><span class="op">)</span>;</span>
<span id="cb40-176"><a href="#cb40-176" aria-hidden="true" tabindex="-1"></a>  <span class="co">// 3 + 3 + ... + 3 = 30</span></span>
<span id="cb40-177"><a href="#cb40-177" aria-hidden="true" tabindex="-1"></a>  <span class="ot">assert</span><span class="op">(</span>result <span class="op">==</span> <span class="fl">30.0</span><span class="bu">f</span><span class="op">)</span>;</span>
<span id="cb40-178"><a href="#cb40-178" aria-hidden="true" tabindex="-1"></a>  <span class="cf">return</span> <span class="dv">0</span>;</span>
<span id="cb40-179"><a href="#cb40-179" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
</div>
</div>
</body>
</html>
