<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<meta name="author" content="Hana+Dus%C3%ADkov%C3%A1">
	<meta name="description" content="">
	<meta name="generator" content="hatemplate/v2">
	<title>P3125R4: constexpr pointer tagging</title>
	
	<link rel="preconnect" href="https://fonts.googleapis.com">
	<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
	
	
<!-- highlight.min.js -->
<script>
/*!
  Highlight.js v11.9.0 (git: b7ec4bfafc)
  (c) 2006-2024 undefined and other contributors
  License: BSD-3-Clause
 */
var hljs=function(){"use strict";function e(t){
return t instanceof Map?t.clear=t.delete=t.set=()=>{
throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{
throw Error("set is read-only")
}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{
const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i)
})),t}class t{constructor(e){
void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1}
ignoreMatch(){this.isMatchIgnored=!0}}function n(e){
return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#x27;")
}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t]
;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope
;class o{constructor(e,t){
this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){
this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{
if(e.startsWith("language:"))return e.replace("language:","language-")
;if(e.includes(".")){const n=e.split(".")
;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ")
}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)}
closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){
this.buffer+=`<span class="${e}">`}}const r=(e={})=>{const t={children:[]}
;return Object.assign(t,e),t};class a{constructor(){
this.rootNode=r(),this.stack=[this.rootNode]}get top(){
return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){
this.top.children.push(e)}openNode(e){const t=r({scope:e})
;this.add(t),this.stack.push(t)}closeNode(){
if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){
for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}
walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){
return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t),
t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){
"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{
a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e}
addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){
this.closeNode()}__addSublanguage(e,t){const n=e.root
;t&&(n.scope="language:"+t),this.add(n)}toHTML(){
return new o(this,this.options).value()}finalize(){
return this.closeAllNodes(),!0}}function l(e){
return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")}
function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")}
function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{
const t=e[e.length-1]
;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{}
})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"}
function p(e){return RegExp(e.toString()+"|").exec("").length-1}
const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./
;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n
;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break}
s+=i.substring(0,e.index),
i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0],
"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)}
const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",w="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",_="\\b(0b[01]+)",O={
begin:"\\\\[\\s\\S]",relevance:0},v={scope:"string",begin:"'",end:"'",
illegal:"\\n",contains:[O]},k={scope:"string",begin:'"',end:'"',illegal:"\\n",
contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t,
contains:[]},n);s.contains.push({scope:"doctag",
begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)",
end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0})
;const o=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/)
;return s.contains.push({begin:h(/[ ]+/,"(",o,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s
},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var j=Object.freeze({
__proto__:null,APOS_STRING_MODE:v,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{
scope:"number",begin:_,relevance:0},BINARY_NUMBER_RE:_,COMMENT:N,
C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number",
begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{
"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{
t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E,
MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0},
NUMBER_MODE:{scope:"number",begin:w,relevance:0},NUMBER_RE:w,
PHRASAL_WORDS_MODE:{
begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/
},QUOTE_STRING_MODE:k,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/,
end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]},
RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",
SHEBANG:(e={})=>{const t=/^#![ ]*\//
;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t,
end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)},
TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x,
UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function A(e,t){
"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){
void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){
t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",
e.__beforeBegin=A,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords,
void 0===e.relevance&&(e.relevance=0))}function L(e,t){
Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){
if(e.match){
if(e.begin||e.end)throw Error("begin & end are not supported with match")
;e.begin=e.match,delete e.match}}function P(e,t){
void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return
;if(e.starts)throw Error("beforeMatch cannot be used with starts")
;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t]
})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={
relevance:0,contains:[Object.assign(n,{endsParent:!0})]
},e.relevance=0,delete n.beforeMatch
},H=["of","and","for","in","not","or","if","then","parent","list","value"],C="keyword"
;function $(e,t,n=C){const i=Object.create(null)
;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{
Object.assign(i,$(e[n],t,n))})),i;function s(e,n){
t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|")
;i[n[0]]=[e,U(n[0],n[1])]}))}}function U(e,t){
return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const z={},W=e=>{
console.error(e)},X=(e,...t)=>{console.log("WARN: "+e,...t)},G=(e,t)=>{
z[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),z[`${e}/${t}`]=!0)
},K=Error();function F(e,t,{key:n}){let i=0;const s=e[n],o={},r={}
;for(let e=1;e<=t.length;e++)r[e+i]=s[e],o[e+i]=!0,i+=p(t[e-1])
;e[n]=r,e[n]._emit=o,e[n]._multi=!0}function Z(e){(e=>{
e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope,
delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={
_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope
}),(e=>{if(Array.isArray(e.begin)){
if(e.skip||e.excludeBegin||e.returnBegin)throw W("skip, excludeBegin, returnBegin not compatible with beginScope: {}"),
K
;if("object"!=typeof e.beginScope||null===e.beginScope)throw W("beginScope must be object"),
K;F(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{
if(Array.isArray(e.end)){
if(e.skip||e.excludeEnd||e.returnEnd)throw W("skip, excludeEnd, returnEnd not compatible with endScope: {}"),
K
;if("object"!=typeof e.endScope||null===e.endScope)throw W("endScope must be object"),
K;F(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function V(e){
function t(t,n){
return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":""))
}class n{constructor(){
this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}
addRule(e,t){
t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]),
this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null)
;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|"
}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex
;const t=this.matcherRe.exec(e);if(!t)return null
;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n]
;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){
this.rules=[],this.multiRegexes=[],
this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){
if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n
;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))),
t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){
return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){
this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){
const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex
;let n=t.exec(e)
;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{
const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)}
return n&&(this.regexIndex+=n.position+1,
this.regexIndex===this.count&&this.considerAll()),n}}
if(e.compilerExtensions||(e.compilerExtensions=[]),
e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language.  See documentation.")
;return e.classNameAliases=i(e.classNameAliases||{}),function n(o,r){const a=o
;if(o.isCompiled)return a
;[I,B,Z,D].forEach((e=>e(o,r))),e.compilerExtensions.forEach((e=>e(o,r))),
o.__beforeBegin=null,[T,L,P].forEach((e=>e(o,r))),o.isCompiled=!0;let c=null
;return"object"==typeof o.keywords&&o.keywords.$pattern&&(o.keywords=Object.assign({},o.keywords),
c=o.keywords.$pattern,
delete o.keywords.$pattern),c=c||/\w+/,o.keywords&&(o.keywords=$(o.keywords,e.case_insensitive)),
a.keywordPatternRe=t(c,!0),
r&&(o.begin||(o.begin=/\B|\b/),a.beginRe=t(a.begin),o.end||o.endsWithParent||(o.end=/\B|\b/),
o.end&&(a.endRe=t(a.end)),
a.terminatorEnd=l(a.end)||"",o.endsWithParent&&r.terminatorEnd&&(a.terminatorEnd+=(o.end?"|":"")+r.terminatorEnd)),
o.illegal&&(a.illegalRe=t(o.illegal)),
o.contains||(o.contains=[]),o.contains=[].concat(...o.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{
variants:null},t)))),e.cachedVariants?e.cachedVariants:q(e)?i(e,{
starts:e.starts?i(e.starts):null
}):Object.isFrozen(e)?i(e):e))("self"===e?o:e)))),o.contains.forEach((e=>{n(e,a)
})),o.starts&&n(o.starts,r),a.matcher=(e=>{const t=new s
;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin"
}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end"
}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function q(e){
return!!e&&(e.endsWithParent||q(e.starts))}class J extends Error{
constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}}
const Y=n,Q=i,ee=Symbol("nomatch"),te=n=>{
const i=Object.create(null),s=Object.create(null),o=[];let r=!0
;const a="Could not find the language '{}', did you forget to load/include a language module?",l={
disableAutodetect:!0,name:"Plain text",contains:[]};let p={
ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i,
languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",
cssSelector:"pre code",languages:null,__emitter:c};function b(e){
return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s=""
;"object"==typeof t?(i=e,
n=t.ignoreIllegals,s=t.language):(G("10.7.0","highlight(lang, code, ...args) has been deprecated."),
G("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),
s=e,i=t),void 0===n&&(n=!0);const o={code:i,language:s};N("before:highlight",o)
;const r=o.result?o.result:E(o.language,o.code,n)
;return r.code=o.code,N("after:highlight",r),r}function E(e,n,s,o){
const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R)
;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n=""
;for(;t;){n+=R.substring(e,t.index)
;const s=_.case_insensitive?t[0].toLowerCase():t[0],o=(i=s,N.keywords[i]);if(o){
const[e,i]=o
;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(j+=i),e.startsWith("_"))n+=t[0];else{
const n=_.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0]
;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i
;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{
if(""===R)return;let e=null;if("string"==typeof N.subLanguage){
if(!i[N.subLanguage])return void M.addText(R)
;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top
}else e=x(R,N.subLanguage.length?N.subLanguage:null)
;N.relevance>0&&(j+=e.relevance),M.__addSublanguage(e._emitter,e.language)
})():l(),R=""}function u(e,t){
""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1
;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue}
const i=_.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}}
function h(e,t){
return e.scope&&"string"==typeof e.scope&&M.openNode(_.classNameAliases[e.scope]||e.scope),
e.beginScope&&(e.beginScope._wrap?(u(R,_.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap),
R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{
value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t)
;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e)
;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){
for(;e.endsParent&&e.parent;)e=e.parent;return e}}
if(e.endsWithParent)return f(e.parent,n,i)}function b(e){
return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){
const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return ee;const o=N
;N.endScope&&N.endScope._wrap?(g(),
u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(),
d(N.endScope,e)):o.skip?R+=t:(o.returnEnd||o.excludeEnd||(R+=t),
g(),o.excludeEnd&&(R=t));do{
N.scope&&M.closeNode(),N.skip||N.subLanguage||(j+=N.relevance),N=N.parent
}while(N!==s.parent);return s.starts&&h(s.starts,e),o.returnEnd?0:t.length}
let w={};function y(i,o){const a=o&&o[0];if(R+=i,null==a)return g(),0
;if("begin"===w.type&&"end"===o.type&&w.index===o.index&&""===a){
if(R+=n.slice(o.index,o.index+1),!r){const t=Error(`0 width match regex (${e})`)
;throw t.languageName=e,t.badRule=w.rule,t}return 1}
if(w=o,"begin"===o.type)return(e=>{
const n=e[0],i=e.rule,s=new t(i),o=[i.__beforeBegin,i["on:begin"]]
;for(const t of o)if(t&&(t(e,s),s.isMatchIgnored))return b(n)
;return i.skip?R+=n:(i.excludeBegin&&(R+=n),
g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(o)
;if("illegal"===o.type&&!s){
const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"')
;throw e.mode=N,e}if("end"===o.type){const e=m(o);if(e!==ee)return e}
if("illegal"===o.type&&""===a)return 1
;if(I>1e5&&I>3*o.index)throw Error("potential infinite loop, way more iterations than matches")
;return R+=a,a.length}const _=O(e)
;if(!_)throw W(a.replace("{}",e)),Error('Unknown language: "'+e+'"')
;const v=V(_);let k="",N=o||v;const S={},M=new p.__emitter(p);(()=>{const e=[]
;for(let t=N;t!==_;t=t.parent)t.scope&&e.unshift(t.scope)
;e.forEach((e=>M.openNode(e)))})();let R="",j=0,A=0,I=0,T=!1;try{
if(_.__emitTokens)_.__emitTokens(n,M);else{for(N.matcher.considerAll();;){
I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=A
;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(A,e.index),e)
;A=e.index+t}y(n.substring(A))}return M.finalize(),k=M.toHTML(),{language:e,
value:k,relevance:j,illegal:!1,_emitter:M,_top:N}}catch(t){
if(t.message&&t.message.includes("Illegal"))return{language:e,value:Y(n),
illegal:!0,relevance:0,_illegalBy:{message:t.message,index:A,
context:n.slice(A-100,A+100),mode:t.mode,resultSoFar:k},_emitter:M};if(r)return{
language:e,value:Y(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N}
;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{
const t={value:Y(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)}
;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(k).map((t=>E(t,e,!1)))
;s.unshift(n);const o=s.sort(((e,t)=>{
if(e.relevance!==t.relevance)return t.relevance-e.relevance
;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1
;if(O(t.language).supersetOf===e.language)return-1}return 0})),[r,a]=o,c=r
;return c.secondBest=a,c}function w(e){let t=null;const n=(e=>{
let t=e.className+" ";t+=e.parentNode?e.parentNode.className:""
;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1])
;return t||(X(a.replace("{}",n[1])),
X("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"}
return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return
;if(N("before:highlightElement",{el:e,language:n
}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e)
;if(e.children.length>0&&(p.ignoreUnescapedHTML,p.throwUnescapedHTML))throw new J("One of your code blocks includes unescaped HTML.",e.innerHTML)
;t=e;const i=t.textContent,o=n?m(i,{language:n,ignoreIllegals:!0}):x(i)
;e.innerHTML=o.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n
;e.classList.add("hljs"),e.classList.add("language-"+i)
})(e,n,o.language),e.result={language:o.language,re:o.relevance,
relevance:o.relevance},o.secondBest&&(e.secondBest={
language:o.secondBest.language,relevance:o.secondBest.relevance
}),N("after:highlightElement",{el:e,result:o,text:i})}let y=!1;function _(){
"loading"!==document.readyState?document.querySelectorAll(p.cssSelector).forEach(w):y=!0
}function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]}
function v(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{
s[e.toLowerCase()]=t}))}function k(e){const t=O(e)
;return t&&!t.disableAutodetect}function N(e,t){const n=e;o.forEach((e=>{
e[n]&&e[n](t)}))}
"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(()=>{
y&&_()}),!1),Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:_,
highlightElement:w,
highlightBlock:e=>(G("10.7.0","highlightBlock will be removed entirely in v12.0"),
G("10.7.0","Please use highlightElement now."),w(e)),configure:e=>{p=Q(p,e)},
initHighlighting:()=>{
_(),G("10.6.0","initHighlighting() deprecated.  Use highlightAll() now.")},
initHighlightingOnLoad:()=>{
_(),G("10.6.0","initHighlightingOnLoad() deprecated.  Use highlightAll() now.")
},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){
if(W("Language definition for '{}' could not be registered.".replace("{}",e)),
!r)throw t;W(t),s=l}
s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&v(s.aliases,{
languageName:e})},unregisterLanguage:e=>{delete i[e]
;for(const t of Object.keys(s))s[t]===e&&delete s[t]},
listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:v,
autoDetection:k,inherit:Q,addPlugin:e=>{(e=>{
e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{
e["before:highlightBlock"](Object.assign({block:t.el},t))
}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{
e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),o.push(e)},
removePlugin:e=>{const t=o.indexOf(e);-1!==t&&o.splice(t,1)}}),n.debugMode=()=>{
r=!1},n.safeMode=()=>{r=!0},n.versionString="11.9.0",n.regex={concat:h,
lookahead:g,either:f,optional:d,anyNumberOfTimes:u}
;for(const t in j)"object"==typeof j[t]&&e(j[t]);return Object.assign(n,j),n
},ne=te({});return ne.newInstance=()=>te({}),ne}()
;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs);/*! `cpp` grammar compiled for Highlight.js 11.9.0 */
(()=>{var e=(()=>{"use strict";return e=>{const t=e.regex,a=e.COMMENT("//","$",{
contains:[{begin:/\\\n/}]
}),n="decltype\\(auto\\)",r="[a-zA-Z_]\\w*::",i="(?!struct)("+n+"|"+t.optional(r)+"[a-zA-Z_]\\w*"+t.optional("<[^<>]+>")+")",s={
className:"type",begin:"\\b[a-z\\d_]*_t\\b"},c={className:"string",variants:[{
begin:'(u8?|U|L)?"',end:'"',illegal:"\\n",contains:[e.BACKSLASH_ESCAPE]},{
begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)",
end:"'",illegal:"."},e.END_SAME_AS_BEGIN({
begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={
className:"number",variants:[{
begin:"[+-]?(?:(?:[0-9](?:'?[0-9])*\\.(?:[0-9](?:'?[0-9])*)?|\\.[0-9](?:'?[0-9])*)(?:[Ee][+-]?[0-9](?:'?[0-9])*)?|[0-9](?:'?[0-9])*[Ee][+-]?[0-9](?:'?[0-9])*|0[Xx](?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*(?:\\.(?:[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)?)?|\\.[0-9A-Fa-f](?:'?[0-9A-Fa-f])*)[Pp][+-]?[0-9](?:'?[0-9])*)(?:[Ff](?:16|32|64|128)?|(BF|bf)16|[Ll]|)"
},{
begin:"[+-]?\\b(?:0[Bb][01](?:'?[01])*|0[Xx][0-9A-Fa-f](?:'?[0-9A-Fa-f])*|0(?:'?[0-7])*|[1-9](?:'?[0-9])*)(?:[Uu](?:LL?|ll?)|[Uu][Zz]?|(?:LL?|ll?)[Uu]?|[Zz][Uu]|)"
}],relevance:0},l={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{
keyword:"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include"
},contains:[{begin:/\\\n/,relevance:0},e.inherit(c,{className:"string"}),{
className:"string",begin:/<.*?>/},a,e.C_BLOCK_COMMENT_MODE]},u={
className:"title",begin:t.optional(r)+e.IDENT_RE,relevance:0
},d=t.optional(r)+e.IDENT_RE+"\\s*\\(",p={
type:["bool","char","char16_t","char32_t","char8_t","double","float","int","long","short","void","wchar_t","unsigned","signed","const","static"],
keyword:["alignas","alignof","and","and_eq","asm","atomic_cancel","atomic_commit","atomic_noexcept","auto","bitand","bitor","break","case","catch","class","co_await","co_return","co_yield","compl","concept","const_cast|10","consteval","constexpr","constinit","continue","decltype","default","delete","do","dynamic_cast|10","else","enum","explicit","export","extern","false","final","for","friend","goto","if","import","inline","module","mutable","namespace","new","noexcept","not","not_eq","nullptr","operator","or","or_eq","override","private","protected","public","reflexpr","register","reinterpret_cast|10","requires","return","sizeof","static_assert","static_cast|10","struct","switch","synchronized","template","this","thread_local","throw","transaction_safe","transaction_safe_dynamic","true","try","typedef","typeid","typename","union","using","virtual","volatile","while","xor","xor_eq"],
literal:["NULL","false","nullopt","nullptr","true"],built_in:["_Pragma"],
_type_hints:["any","auto_ptr","barrier","binary_semaphore","bitset","complex","condition_variable","condition_variable_any","counting_semaphore","deque","false_type","future","imaginary","initializer_list","istringstream","jthread","latch","lock_guard","multimap","multiset","mutex","optional","ostringstream","packaged_task","pair","promise","priority_queue","queue","recursive_mutex","recursive_timed_mutex","scoped_lock","set","shared_future","shared_lock","shared_mutex","shared_timed_mutex","shared_ptr","stack","string_view","stringstream","timed_mutex","thread","true_type","tuple","unique_lock","unique_ptr","unordered_map","unordered_multimap","unordered_multiset","unordered_set","variant","vector","weak_ptr","wstring","wstring_view"]
},_={className:"function.dispatch",relevance:0,keywords:{
_hint:["abort","abs","acos","apply","as_const","asin","atan","atan2","calloc","ceil","cerr","cin","clog","cos","cosh","cout","declval","endl","exchange","exit","exp","fabs","floor","fmod","forward","fprintf","fputs","free","frexp","fscanf","future","invoke","isalnum","isalpha","iscntrl","isdigit","isgraph","islower","isprint","ispunct","isspace","isupper","isxdigit","labs","launder","ldexp","log","log10","make_pair","make_shared","make_shared_for_overwrite","make_tuple","make_unique","malloc","memchr","memcmp","memcpy","memset","modf","move","pow","printf","putchar","puts","realloc","scanf","sin","sinh","snprintf","sprintf","sqrt","sscanf","std","stderr","stdin","stdout","strcat","strchr","strcmp","strcpy","strcspn","strlen","strncat","strncmp","strncpy","strpbrk","strrchr","strspn","strstr","swap","tan","tanh","terminate","to_underlying","tolower","toupper","vfprintf","visit","vprintf","vsprintf"]
},
begin:t.concat(/\b/,/(?!decltype)/,/(?!if)/,/(?!for)/,/(?!switch)/,/(?!while)/,e.IDENT_RE,t.lookahead(/(<[^<>]+>|)\s*\(/))
},m=[_,l,s,a,e.C_BLOCK_COMMENT_MODE,o,c],f={variants:[{begin:/=/,end:/;/},{
begin:/\(/,end:/\)/},{beginKeywords:"new throw return else",end:/;/}],
keywords:p,contains:m.concat([{begin:/\(/,end:/\)/,keywords:p,
contains:m.concat(["self"]),relevance:0}]),relevance:0},g={className:"function",
begin:"("+i+"[\\*&\\s]+)+"+d,returnBegin:!0,end:/[{;=]/,excludeEnd:!0,
keywords:p,illegal:/[^\w\s\*&:<>.]/,contains:[{begin:n,keywords:p,relevance:0},{
begin:d,returnBegin:!0,contains:[u],relevance:0},{begin:/::/,relevance:0},{
begin:/:/,endsWithParent:!0,contains:[c,o]},{relevance:0,match:/,/},{
className:"params",begin:/\(/,end:/\)/,keywords:p,relevance:0,
contains:[a,e.C_BLOCK_COMMENT_MODE,c,o,s,{begin:/\(/,end:/\)/,keywords:p,
relevance:0,contains:["self",a,e.C_BLOCK_COMMENT_MODE,c,o,s]}]
},s,a,e.C_BLOCK_COMMENT_MODE,l]};return{name:"C++",
aliases:["cc","c++","h++","hpp","hh","hxx","cxx"],keywords:p,illegal:"</",
classNameAliases:{"function.dispatch":"built_in"},
contains:[].concat(f,g,_,m,[l,{
begin:"\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)",
end:">",keywords:p,contains:["self",s]},{begin:e.IDENT_RE+"::",keywords:p},{
match:[/\b(?:enum(?:\s+(?:class|struct))?|class|struct|union)/,/\s+/,/\w+/],
className:{1:"keyword",3:"title.class"}}])}}})();hljs.registerLanguage("cpp",e)
})();
</script>

<!-- merge-html.js -->
<script>
var mergeHTMLPlugin = (function () {
  'use strict';

  var originalStream;

  /**
   * @param {string} value
   * @returns {string}
   */
  function escapeHTML(value) {
    return value
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#x27;');
  }

  /* plugin itself */

  /** @type {HLJSPlugin} */
  const mergeHTMLPlugin = {
    // preserve the original HTML token stream
    "before:highlightElement": ({ el }) => {
      originalStream = nodeStream(el);
    },
    // merge it afterwards with the highlighted token stream
    "after:highlightElement": ({ el, result, text }) => {
      if (!originalStream.length) return;

      const resultNode = document.createElement('div');
      resultNode.innerHTML = result.value;
      result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
      el.innerHTML = result.value;
    }
  };

  /* Stream merging support functions */

  /**
   * @typedef Event
   * @property {'start'|'stop'} event
   * @property {number} offset
   * @property {Node} node
   */

  /**
   * @param {Node} node
   */
  function tag(node) {
    return node.nodeName.toLowerCase();
  }

  /**
   * @param {Node} node
   */
  function nodeStream(node) {
    /** @type Event[] */
    const result = [];
    (function _nodeStream(node, offset) {
      for (let child = node.firstChild; child; child = child.nextSibling) {
        if (child.nodeType === 3) {
          offset += child.nodeValue.length;
        } else if (child.nodeType === 1) {
          result.push({
            event: 'start',
            offset: offset,
            node: child
          });
          offset = _nodeStream(child, offset);
          // Prevent void elements from having an end tag that would actually
          // double them in the output. There are more void elements in HTML
          // but we list only those realistically expected in code display.
          if (!tag(child).match(/br|hr|img|input/)) {
            result.push({
              event: 'stop',
              offset: offset,
              node: child
            });
          }
        }
      }
      return offset;
    })(node, 0);
    return result;
  }

  /**
   * @param {any} original - the original stream
   * @param {any} highlighted - stream of the highlighted source
   * @param {string} value - the original source itself
   */
  function mergeStreams(original, highlighted, value) {
    let processed = 0;
    let result = '';
    const nodeStack = [];

    function selectStream() {
      if (!original.length || !highlighted.length) {
        return original.length ? original : highlighted;
      }
      if (original[0].offset !== highlighted[0].offset) {
        return (original[0].offset < highlighted[0].offset) ? original : highlighted;
      }

      /*
      To avoid starting the stream just before it should stop the order is
      ensured that original always starts first and closes last:

      if (event1 == 'start' && event2 == 'start')
        return original;
      if (event1 == 'start' && event2 == 'stop')
        return highlighted;
      if (event1 == 'stop' && event2 == 'start')
        return original;
      if (event1 == 'stop' && event2 == 'stop')
        return highlighted;

      ... which is collapsed to:
      */
      return highlighted[0].event === 'start' ? original : highlighted;
    }

    /**
     * @param {Node} node
     */
    function open(node) {
      /** @param {Attr} attr */
      function attributeString(attr) {
        return ' ' + attr.nodeName + '="' + escapeHTML(attr.value) + '"';
      }
      // @ts-ignore
      result += '<' + tag(node) + [].map.call(node.attributes, attributeString).join('') + '>';
    }

    /**
     * @param {Node} node
     */
    function close(node) {
      result += '</' + tag(node) + '>';
    }

    /**
     * @param {Event} event
     */
    function render(event) {
      (event.event === 'start' ? open : close)(event.node);
    }

    while (original.length || highlighted.length) {
      let stream = selectStream();
      result += escapeHTML(value.substring(processed, stream[0].offset));
      processed = stream[0].offset;
      if (stream === original) {
        /*
        On any opening or closing tag of the original markup we first close
        the entire highlighted node stack, then render the original tag along
        with all the following original tags at the same offset and then
        reopen all the tags on the highlighted stack.
        */
        nodeStack.reverse().forEach(close);
        do {
          render(stream.splice(0, 1)[0]);
          stream = selectStream();
        } while (stream === original && stream.length && stream[0].offset === processed);
        nodeStack.reverse().forEach(open);
      } else {
        if (stream[0].event === 'start') {
          nodeStack.push(stream[0].node);
        } else {
          nodeStack.pop();
        }
        render(stream.splice(0, 1)[0]);
      }
    }
    return result + escapeHTML(value.substr(processed));
  }

  return mergeHTMLPlugin;

}());
</script>

<!-- trim-nicely.js -->
<script>
var trimNicely = (function () {
  'use strict';

	// this is code from reveal.js under following license:
	
	// Copyright (C) 2011-2024 Hakim El Hattab, http://hakim.se, and reveal.js contributors
  // 
	// Permission is hereby granted, free of charge, to any person obtaining a copy
	// of this software and associated documentation files (the "Software"), to deal
	// in the Software without restriction, including without limitation the rights
	// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	// copies of the Software, and to permit persons to whom the Software is
	// furnished to do so, subject to the following conditions:
  // 
	// The above copyright notice and this permission notice shall be included in
	// all copies or substantial portions of the Software.
  // 
	// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	// THE SOFTWARE.

	// Function to perform a better "data-trim" on code snippets
	// Will slice an indentation amount on each line of the snippet (amount based on the line having the lowest indentation length)
	function betterTrim(snippetEl) {
		// Helper functions
		function trimLeft(val) {
			// Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
			return val.replace(/^[\s\uFEFF\xA0]+/g, '');
		}
		function trimLineBreaks(input) {
			//console.log(input);
			var lines = input.split("\n");

			// Trim line-breaks from the beginning
			for (var i = 0; i < lines.length; i++) {
				if (lines[i].trim() === '') {
					lines.splice(i--, 1);
				} else break;
			}

			// Trim line-breaks from the end
			for (var i = lines.length-1; i >= 0; i--) {
				if (lines[i].trim() === '') {
					lines.splice(i, 1);
				} else break;
			}

			return lines.join("\n");
		}

		// Main function for betterTrim()
		return (function(snippetEl) {
			var content = trimLineBreaks(snippetEl.innerHTML);
			var lines = content.split("\n");
			// Calculate the minimum amount to remove on each line start of the snippet (can be 0)
			var pad = lines.reduce(function(acc, line) {
				if (line.length > 0 && trimLeft(line).length > 0 && acc > line.length - trimLeft(line).length) {
					return line.length - trimLeft(line).length;
				}
				return acc;
			}, Number.POSITIVE_INFINITY);
			// Slice each line with this amount
			return lines.map(function(line, index) {
				return line.slice(pad);
			})
			.join("\n");
		})(snippetEl);
	}
	

  /** @type {HLJSPlugin} */
  const trimNicely = {
    // preserve the original HTML token stream
    "before:highlightElement": ({ el }) => {
			if (!el.hasAttribute("no-data-trim")) {
				el.innerHTML = betterTrim(el);
			}
			
    },
    // merge it afterwards with the highlighted token stream
    "after:highlightElement": ({ el, result, text }) => {
      //if (!originalStream.length) return;
      //
      //const resultNode = document.createElement('div');
      //resultNode.innerHTML = result.value;
      //result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
      //el.innerHTML = result.value;
    }
  };

  /* Stream merging support functions */

  

  return trimNicely;

}());
</script>

	
<!-- Noto Serif (external font) -->
<link href="https://fonts.googleapis.com/css?family=Noto+Serif" rel="stylesheet" blocking="render"></link>
	
<!-- Noto Sans (external font) -->
<link href="https://fonts.googleapis.com/css?family=Noto+Sans" rel="stylesheet" blocking="render"></link>
	
	
<!-- Fira Code (external font) -->
<link href="https://fonts.googleapis.com/css?family=Fira+Code" rel="stylesheet" blocking="render"></link>
	
<!-- eel-hana.css -->
<style>
.wording  {
    font-family: 'Noto Serif';
    hyphens: auto;
    line-height: 1.5;
    font-size: var(--base-font-size-10);
    padding-left: 3em;
}

.wording div {
    background: inherit;
}

.wording div.wrapper {
    max-width: 20cm;
    margin: auto;
}

.wording div.texpara {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording table div.texpara {
    margin-top: 0;
    margin-bottom: 0;
}

.wording table.enumerate div.texpara {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording ul {
    list-style-type: none;
    padding-left: 9mm;
    margin-top: 0;
    margin-bottom: 0;
}

.wording ol {
    margin-top: 0;
    margin-bottom: 0;
}

.wording a {
    text-decoration: none;
}

.wording a.hidden_link {
    text-decoration: none;
    color: inherit;
}

.wording li {
    margin-top: 3pt;
    margin-bottom: 3pt;
}

.wording h1 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h2 {
    line-height: 1;
    font-size: var(--base-font-size-14);
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h2::after {
    content: "";
    clear: both;
    display: table;
}

.wording h3 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h3::after {
    content: "";
    clear: both;
    display: table;
}

.wording h4 {
    line-height: 1;
    margin-top: 10pt;
    margin-bottom: 10pt;
}

.wording h4::after {
    content: "";
    clear: both;
    display: table;
}

.wording ul > li:before {
    content: "\2014";
    position: absolute;
    margin-left: -1.5em;
}

.wording .shy:before {
    content: "\00ad";
    /* This is U+00AD SOFT HYPHEN, same as &shy, but we put it in :before
    	to stop it from being included when the text is copied to the clipboard
    	with Firefox, which is especially annoying when copying to a terminal,
    	where the hyphen characters will show up. */
}


.wording .abbr_ref {
    float: right;
}

.wording .folded_abbr_ref {
    float: right;
}

.wording .unfolded_abbr_ref {
    display: none;
}

.wording .secnum {
    display: inline-block;
    min-width: 35pt;
}

.wording .annexnum {
    display: block;
}

.wording div.sourceLinkParent {
    float: right;
}

.wording a.sourceLink {
    position: absolute;
    opacity: 0;
    margin-left: 10pt;
}

.wording a.sourceLink:hover {
    opacity: 1;
}

.wording a.itemDeclLink {
    position: absolute;
    font-size: 75%;
    text-align: right;
    width: 5em;
    opacity: 0;
}

.wording a.itemDeclLink:hover {
    opacity: 1;
}

.wording div.marginalizedparent {
    position: relative;
    left: -18mm;
}

.wording a.marginalized {
    width: 15mm;
    position: absolute;
    font-size: var(--base-font-size-7);
    text-align: right;
}

.wording a.enumerated_item_num {
    display: block;
    margin-top: 3pt;
    margin-bottom: 3pt;
    margin-right: 6pt;
}

.wording div.para {
    margin-bottom: 6pt;
    margin-top: 6pt;
    text-align: justify;
    min-height: 1.2em;
}

.wording div.section {
    text-align: justify;
}

.wording div.sentence {
    display: inline;
}

.wording a.index {
    position: relative;
    float: right;
    right: -1em;
    display: none;
}

.wording a.index:before {
    position: absolute;
    content: "⟵";
    background-color: #C9FBC9;
}


.wording .indexitems {
    margin-left: 2em;
    text-indent: -2em;
}

.wording div.itemdescr {
    margin-left: 12mm;
}

.wording .bnf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
    font-style: italic;
    margin-left: 25pt;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    text-indent: -3em;
    padding-left: 3em;
    line-height: 1.5;
}

.wording div.bnf span.texttt {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording .rebnf {
    font-family: 'Noto Serif';
    font-style: italic;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    margin-left: 30pt;
    text-indent: -3em;
    padding-left: 3em;
    line-height: 1.5;
}

.wording .simplebnf {
    font-family: 'Noto Serif';
    font-style: italic;
    font-size: var(--base-font-size-10);
    margin-top: 0.5em;
    margin-bottom: 0.5em;
    margin-left: 30pt;
    line-height: 1.5;
}

.wording span.textnormal {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
    white-space: normal;
}

.wording .bnf span.textnormal {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
    white-space: normal;
}

.wording p {
    margin-top: 4pt;
    margin-bottom: 4pt;
}

.wording span.rlap {
    display: inline-block;
    width: 0px;
    text-indent: 0;
}

.wording span.terminal {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
    white-space: pre-wrap;
}

.wording span.noncxxterminal {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
}

.wording span.term {
    font-style: italic;
}

.wording span.tcode {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.textbf {
    font-weight: bold;
}

.wording span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording div.footnote span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-8);
}

.wording .bnf span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .simplebnf span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .example span.textsf {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording span.textsc {
    font-variant: small-caps;
}

.wording span.nontermdef {
    font-style: italic;
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .rebnf a.nontermdef {
    font-style: italic;
    font-family: 'Noto Serif';
}

.wording span.emph {
    font-style: italic;
}

.wording span.techterm {
    font-style: italic;
}

.wording span.mathit {
    font-style: italic;
}

.wording span.mathsf {
    font-family: 'Noto Sans';
}

.wording span.mathrm {
    font-family: 'Noto Serif';
    font-style: normal;
}

.wording span.textrm {
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording span.textsl {
    font-style: italic;
}

.wording span.mathtt {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.mbox {
    font-family: 'Noto Serif';
    font-style: normal;
}

.wording span.ungap {
    display: inline-block;
    width: 2pt;
}

.wording span.texttt {
    font-family: 'Noto Sans Mono';
}

.wording span.textit {
    font-style: italic;
}

.wording div.footnote span.texttt {
    font-family: 'Noto Sans Mono';
}

.wording span.tcode_in_codeblock {
    font-family: 'Noto Sans Mono';
    font-style: normal;
    font-size: var(--base-font-size-9);
}

.wording span.phantom {
    color: white;
}
/* Unfortunately, this way the text is still selectable. Another
	option is display:none, but then we lose the nice layout.
	Todo: find proper solution. */

.wording span.math {
    font-style: normal;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording span.mathblock {
    display: block;
    margin-left: auto;
    margin-right: auto;
    margin-top: 1.2em;
    margin-bottom: 1.2em;
    text-align: center;
}

.wording span.mathalpha {
    font-style: italic;
}

.wording span.synopsis {
    font-weight: bold;
    margin-top: 0.5em;
    display: block;
}

.wording span.definition {
    font-weight: bold;
    display: block;
}

.wording .codeblock {
    font-family: 'Noto Sans Mono';
    margin-left: 1.2em;
    line-height: 1.5;
    font-size: var(--base-font-size-9);
    white-space: pre;
    display: block;
    margin-top: 3pt;
    margin-bottom: 3pt;
		overflow-x: visible;
		overflow-y: default;
}

.wording table .codeblock {
    margin-right: 0;
}

.wording .outputblock {
    margin-left: 1.2em;
    line-height: 1.5;
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-9);
}

.wording code {
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording div.itemdecl {
    margin-top: 2ex;
}

.wording code.itemdeclcode {
    white-space: pre;
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-9);
    display: block;
		overflow-x: visible;
		overflow-y: default;
}

.wording .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-10);
}

.wording .footnote .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-8);
}

.wording .example .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-9);
}

.wording .note .comment {
    color: green;
    font-style: italic;
    font-family: 'Noto Serif';
    font-size: var(--base-font-size-9);
}

.wording span.keyword {
    color: #00607c;
    font-style: normal;
}

.wording span.parenthesis {
    color: #af1915;
}

.wording span.curlybracket {
    color: #af1915;
}

.wording span.squarebracket {
    color: #af1915;
}

.wording span.literal {
    color: #9F6807;
}

.wording span.literalterminal {
    color: #9F6807;
    font-family: 'Noto Sans Mono';
    font-style: normal;
}

.wording span.operator {
    color: #570057;
}

.wording span.anglebracket {
    color: #570057;
}

.wording span.preprocessordirective {
    color: #6F4E37;
}

.wording span.textsuperscript {
    vertical-align: super;
    font-size: smaller;
    line-height: 0;
}

.wording .footnoteref {
    vertical-align: super;
    font-size: smaller;
    line-height: 0;
}

.wording .footnote {
    font-size: var(--base-font-size-8);
}

.wording .footnote .math {
    font-size: var(--base-font-size-8);
}

.wording .footnotenum {
    display: inline-block;
    text-align: right;
    margin-right: 1mm;
    width: 4ch;
}

.wording .footnoteBacklink {
    display: none;
}

.wording .footnoteSeparator {
    background: black;
    margin-top: 5mm;
    height: 1px;
    width: 6cm;
}

.wording div.minipage {
    display: inline-block;
    margin-right: 3em;
}

.wording div.numberedTable {
    text-align: center;
    margin-left: 1em;
    margin-right: 1em;
    margin-bottom: 12pt;
    margin-top: 8pt;
}

.wording div.figure {
    text-align: center;
    margin-left: 2em;
    margin-right: 2em;
    margin-bottom: 12pt;
    margin-top: 3pt;
}

.wording table {
    border: 1px solid black;
    border-collapse: collapse;
    margin-left: auto;
    margin-right: auto;
    margin-top: 7pt;
    text-align: left;
}

.wording td, .wording th {
    padding-left: 8pt;
    padding-right: 8pt;
    vertical-align: top;
}

.wording td.empty {
    padding: 0px;
    padding-left: 1px;
}

.wording td.left {
    text-align: left;
}

.wording td.hidden {
    padding: 0;
    width: 0;
}

.wording td.right {
    text-align: right;
}

.wording td.center {
    text-align: center;
}

.wording td.justify {
    text-align: justify;
}

.wording td.border {
    border-left: 1px solid black;
}

.wording tr.rowsep, .wording td.cline {
    border-top: 1px solid black;
}

.wording tr.capsep {
    border-top: 3px solid black;
    border-top-style: double;
}

.wording th {
    border-bottom: 1px solid black;
}

.wording span.centry {
    font-weight: bold;
}

.wording div.table {
    display: block;
    margin-left: auto;
    margin-right: auto;
    text-align: center;
    width: 90%;
}

.wording span.indented {
    background: inherit;
    display: block;
    margin-left: 2em;
    margin-bottom: 1em;
    margin-top: 1em;
}

.wording span.uppercase {
    text-transform: uppercase;
}

.wording span.ucode {
    font-variant: small-caps;
    text-transform: uppercase;
    font-size: 90%;
}

.wording span.uname {
    font-variant: small-caps;
    text-transform: uppercase;
    font-size: 90%;
}

.wording table.enumerate {
    border: 0;
    margin: 0;
}

.wording table.enumerate td {
    padding: 0;
}

.wording table.enumerate td:first-child {
    width: 1cm;
    text-align: right;
}

@media (prefers-color-scheme: dark) {
    .wording {
        background-color: #171717;
        color: #d0d0d0;
    }

    .wording span.mjx-mstyle {
        color: #d0d0d0 !important
    }

    .wording a.hidden_link {
        text-decoration: none;
        color: inherit;
    }

    .wording span.phantom {
        color: #171717;
    }

    .wording a.index:before {
        color: #d0d0d0;
        background-color: #4b6353;
    }

    .wording .comment {
        color: #35da00;
    }

    .wording .footnote .comment {
        color: #35da00;
    }

    .wording .example .comment {
        color: #35da00;
    }

    .wording .note .comment {
        color: #35da00;
    }

    .wording span.keyword {
        color: #12cabe;
    }

    .wording span.parenthesis {
        color: #ff1515;
    }

    .wording span.curlybracket {
        color: #ff1515;
    }

    .wording span.squarebracket {
        color: #ff1515;
    }

    .wording span.literal {
        color: #dfa837;
    }

    .wording span.literalterminal {
        color: #dfa837;
    }

    .wording span.operator {
        color: #baa6b9;
    }

    .wording span.anglebracket {
        color: #baa6b9;
    }

    .wording span.preprocessordirective {
        color: #b27c58;
    }

    .wording table {
        border-color: #d0d0d0;
    }

    .wording td.border {
        border-color: #d0d0d0;
    }

    .wording td.border {
        border-left-color: #d0d0d0;
    }

    .wording tr.rowsep, td.cline {
        border-top-color: #d0d0d0;
    }

    .wording tr.capsep {
        border-top-color: #d0d0d0;
    }

    .wording th {
        border-bottom-color: #d0d0d0;
    }

    .wording .footnoteSeparator {
        background-color: #d0d0d0;
    }

    .wording text {
        fill: #d0d0d0;
    }

    .wording path {
        stroke: #d0d0d0;
    }

    .wording polygon {
        stroke: #d0d0d0;
        fill: #d0d0d0;
    }

    .wording ellipse {
        stroke: #d0d0d0;
    }

}

.wording .mjx-chtml {
    display: inline-block;
    line-height: 0;
    text-indent: 0;
    text-align: left;
    text-transform: none;
    font-style: normal;
    font-weight: normal;
    font-size: 100%;
    font-size-adjust: none;
    letter-spacing: normal;
    word-wrap: normal;
    word-spacing: normal;
    white-space: nowrap;
    float: none;
    direction: ltr;
    max-width: none;
    max-height: none;
    min-width: 0;
    min-height: 0;
    border: 0;
    margin: 0;
    padding: 1px 0
}

.wording .MJXc-display {
    display: block;
    background: inherit;
    text-align: center;
    margin: 1em 0;
    padding: 0
}

.wording .mjx-chtml[tabindex]:focus, .wording  :focus .mjx-chtml[tabindex] {
    display: inline-table
}

.wording .mjx-full-width {
    text-align: center;
    display: table-cell !important;
    width: 10000em
}

.wording .mjx-math {
    display: inline-block;
    border-collapse: separate;
    border-spacing: 0
}

.wording .mjx-math * {
    display: inline-block;
    -webkit-box-sizing: content-box !important;
    -moz-box-sizing: content-box !important;
    box-sizing: content-box !important;
    text-align: left
}

.wording .mjx-numerator {
    display: block;
    background: inherit;
    text-align: center
}

.wording .mjx-denominator {
    display: block;
    background: inherit;
    text-align: center
}

.wording .MJXc-stacked {
    height: 0;
    position: relative
}

.wording .MJXc-stacked > * {
    position: absolute
}

.wording .MJXc-bevelled > * {
    display: inline-block
}

.wording .mjx-stack {
    display: inline-block
}

.wording .mjx-op {
    display: block;
    background: inherit
}

.wording .mjx-under {
    display: table-cell
}

.wording .mjx-over {
    display: block;
    background: inherit
}

.wording .mjx-over > * {
    padding-left: 0px !important;
    padding-right: 0px !important
}

.wording .mjx-under > * {
    padding-left: 0px !important;
    padding-right: 0px !important
}

.wording .mjx-stack > .mjx-sup {
    display: block;
    background: inherit
}

.wording .mjx-stack > .mjx-sub {
    display: block;
    background: inherit
}

.wording .mjx-prestack > .mjx-presup {
    display: block;
    background: inherit
}

.wording .mjx-prestack > .mjx-presub {
    display: block;
    background: inherit
}

.wording .mjx-delim-h > .mjx-char {
    display: inline-block
}

.wording .mjx-surd {
    vertical-align: top
}

.wording .mjx-mphantom * {
    visibility: hidden
}

.wording .mjx-merror {
    background-color: #FFFF88;
    color: #CC0000;
    border: 1px solid #CC0000;
    padding: 2px 3px;
    font-style: normal;
    font-size: 90%
}

.wording .mjx-annotation-xml {
    line-height: normal
}

.wording .mjx-menclose > svg {
    fill: none;
    stroke: currentColor
}

.wording .mjx-mtr {
    display: table-row
}

.wording .mjx-mlabeledtr {
    display: table-row
}

.wording .mjx-mtd {
    display: table-cell;
    text-align: center
}

.wording .mjx-label {
    display: table-row
}

.wording .mjx-box {
    display: inline-block
}

.wording .mjx-block {
    display: block;
    background: inherit
}

.wording .mjx-span {
    display: inline
}

.wording .mjx-char {
    display: block;
    background: inherit;
    white-space: pre
}

.wording .mjx-itable {
    display: inline-table;
    width: auto
}

.wording .mjx-row {
    display: table-row
}

.wording .mjx-cell {
    display: table-cell
}

.wording .mjx-table {
    display: table;
    width: 100%
}

.wording .mjx-line {
    display: block;
    background: inherit;
    height: 0
}

.wording .mjx-strut {
    width: 0;
    padding-top: 1em
}

.wording .mjx-vsize {
    width: 0
}

.wording .MJXc-space1 {
    margin-left: .167em
}

.wording .MJXc-space2 {
    margin-left: .222em
}

.wording .MJXc-space3 {
    margin-left: .278em
}

.wording .mjx-ex-box-test {
    position: absolute;
		overflow-x: visible;
		overflow-y: default;
    width: 1px;
    height: 60ex
}

.wording .mjx-line-box-test {
    display: table !important
}

.wording .mjx-line-box-test span {
    display: table-cell !important;
    width: 10000em !important;
    min-width: 0;
    max-width: none;
    padding: 0;
    border: 0;
    margin: 0
}

.wording .MJXc-TeX-unknown-R {
    font-family: monospace;
    font-style: normal;
    font-weight: normal
}

.wording .MJXc-TeX-unknown-I {
    font-family: monospace;
    font-style: italic;
    font-weight: normal
}

.wording .MJXc-TeX-unknown-B {
    font-family: monospace;
    font-style: normal;
    font-weight: bold
}

.wording .MJXc-TeX-unknown-BI {
    font-family: monospace;
    font-style: italic;
    font-weight: bold
}

.wording .MJXc-TeX-ams-R {
    font-family: MJXc-TeX-ams-R, MJXc-TeX-ams-Rw
}

.wording .MJXc-TeX-cal-B {
    font-family: MJXc-TeX-cal-B, MJXc-TeX-cal-Bx, MJXc-TeX-cal-Bw
}

.wording .MJXc-TeX-frak-R {
    font-family: MJXc-TeX-frak-R, MJXc-TeX-frak-Rw
}

.wording .MJXc-TeX-frak-B {
    font-family: MJXc-TeX-frak-B, MJXc-TeX-frak-Bx, MJXc-TeX-frak-Bw
}

.wording .MJXc-TeX-math-BI {
    font-family: MJXc-TeX-math-BI, MJXc-TeX-math-BIx, MJXc-TeX-math-BIw
}

.wording .MJXc-TeX-sans-R {
    font-family: 'Noto Sans';
    font-size: var(--base-font-size-10);
}

.wording .MJXc-TeX-sans-B {
    font-family: MJXc-TeX-sans-B, MJXc-TeX-sans-Bx, MJXc-TeX-sans-Bw
}

.wording .MJXc-TeX-sans-I {
    font-family: MJXc-TeX-sans-I, MJXc-TeX-sans-Ix, MJXc-TeX-sans-Iw
}

.wording .MJXc-TeX-script-R {
    font-family: MJXc-TeX-script-R, MJXc-TeX-script-Rw
}

.wording .MJXc-TeX-type-R {
    font-family: 'Noto Sans Mono';
    font-size: var(--base-font-size-10);
}

.wording .MJXc-TeX-cal-R {
    font-family: MJXc-TeX-cal-R, MJXc-TeX-cal-Rw
}

.wording .MJXc-TeX-main-B {
    font-family: MJXc-TeX-main-B, MJXc-TeX-main-Bx, MJXc-TeX-main-Bw
}

.wording .MJXc-TeX-main-I {
    font-style: italic
}

.wording .MJXc-TeX-main-R {
}

.wording .MJXc-TeX-math-I {
    font-style: italic
}

.wording .MJXc-TeX-size1-R {
    font-family: MJXc-TeX-size1-R, MJXc-TeX-size1-Rw
}

.wording .MJXc-TeX-size2-R {
    font-family: MJXc-TeX-size2-R, MJXc-TeX-size2-Rw
}

.wording .MJXc-TeX-size3-R {
    font-family: MJXc-TeX-size3-R, MJXc-TeX-size3-Rw
}

.wording .MJXc-TeX-size4-R {
    font-family: MJXc-TeX-size4-R, MJXc-TeX-size4-Rw
}

.wording .MJXc-TeX-vec-R {
    font-family: MJXc-TeX-vec-R, MJXc-TeX-vec-Rw
}

.wording .MJXc-TeX-vec-B {
    font-family: MJXc-TeX-vec-B, MJXc-TeX-vec-Bx, MJXc-TeX-vec-Bw
}

@font-face {
    font-family: MJXc-TeX-ams-R;
    src: local('MathJax_AMS'), local('MathJax_AMS-Regular')
}

@font-face {
    font-family: MJXc-TeX-ams-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_AMS-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_AMS-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_AMS-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-cal-B;
    src: local('MathJax_Caligraphic Bold'), local('MathJax_Caligraphic-Bold')
}

@font-face {
    font-family: MJXc-TeX-cal-Bx;
    src: local('MathJax_Caligraphic');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-cal-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-frak-R;
    src: local('MathJax_Fraktur'), local('MathJax_Fraktur-Regular')
}

@font-face {
    font-family: MJXc-TeX-frak-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-frak-B;
    src: local('MathJax_Fraktur Bold'), local('MathJax_Fraktur-Bold')
}

@font-face {
    font-family: MJXc-TeX-frak-Bx;
    src: local('MathJax_Fraktur');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-frak-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Fraktur-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Fraktur-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Fraktur-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-math-BI;
    src: local('MathJax_Math BoldItalic'), local('MathJax_Math-BoldItalic')
}

@font-face {
    font-family: MJXc-TeX-math-BIx;
    src: local('MathJax_Math');
    font-weight: bold;
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-math-BIw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Math-BoldItalic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Math-BoldItalic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Math-BoldItalic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-R;
    src: local('MathJax_SansSerif'), local('MathJax_SansSerif-Regular')
}

@font-face {
    font-family: MJXc-TeX-sans-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-B;
    src: local('MathJax_SansSerif Bold'), local('MathJax_SansSerif-Bold')
}

@font-face {
    font-family: MJXc-TeX-sans-Bx;
    src: local('MathJax_SansSerif');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-sans-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-sans-I;
    src: local('MathJax_SansSerif Italic'), local('MathJax_SansSerif-Italic')
}

@font-face {
    font-family: MJXc-TeX-sans-Ix;
    src: local('MathJax_SansSerif');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-sans-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_SansSerif-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_SansSerif-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_SansSerif-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-script-R;
    src: local('MathJax_Script'), local('MathJax_Script-Regular')
}

@font-face {
    font-family: MJXc-TeX-script-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Script-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Script-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Script-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-type-R;
    src: local('MathJax_Typewriter'), local('MathJax_Typewriter-Regular')
}

@font-face {
    font-family: MJXc-TeX-type-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Typewriter-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Typewriter-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Typewriter-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-cal-R;
    src: local('MathJax_Caligraphic'), local('MathJax_Caligraphic-Regular')
}

@font-face {
    font-family: MJXc-TeX-cal-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Caligraphic-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Caligraphic-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Caligraphic-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-B;
    src: local('MathJax_Main Bold'), local('MathJax_Main-Bold')
}

@font-face {
    font-family: MJXc-TeX-main-Bx;
    src: local('MathJax_Main');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-main-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Bold.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-I;
    src: local('MathJax_Main Italic'), local('MathJax_Main-Italic')
}

@font-face {
    font-family: MJXc-TeX-main-Ix;
    src: local('MathJax_Main');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-main-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-main-R;
    src: local('MathJax_Main'), local('MathJax_Main-Regular')
}

@font-face {
    font-family: MJXc-TeX-main-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Main-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Main-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-math-I;
    src: local('MathJax_Math Italic'), local('MathJax_Math-Italic')
}

@font-face {
    font-family: MJXc-TeX-math-Ix;
    src: local('MathJax_Math');
    font-style: italic
}

@font-face {
    font-family: MJXc-TeX-math-Iw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Math-Italic.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Math-Italic.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size1-R;
    src: local('MathJax_Size1'), local('MathJax_Size1-Regular')
}

@font-face {
    font-family: MJXc-TeX-size1-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size1-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size1-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size1-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size2-R;
    src: local('MathJax_Size2'), local('MathJax_Size2-Regular')
}

@font-face {
    font-family: MJXc-TeX-size2-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size2-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size2-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size2-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size3-R;
    src: local('MathJax_Size3'), local('MathJax_Size3-Regular')
}

@font-face {
    font-family: MJXc-TeX-size3-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size3-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size3-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size3-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-size4-R;
    src: local('MathJax_Size4'), local('MathJax_Size4-Regular')
}

@font-face {
    font-family: MJXc-TeX-size4-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Size4-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Size4-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Size4-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-vec-R;
    src: local('MathJax_Vector'), local('MathJax_Vector-Regular')
}

@font-face {
    font-family: MJXc-TeX-vec-Rw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Regular.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Regular.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Regular.otf') format('opentype')
}

@font-face {
    font-family: MJXc-TeX-vec-B;
    src: local('MathJax_Vector Bold'), local('MathJax_Vector-Bold')
}

@font-face {
    font-family: MJXc-TeX-vec-Bx;
    src: local('MathJax_Vector');
    font-weight: bold
}

@font-face {
    font-family: MJXc-TeX-vec-Bw;
    src /*1*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/eot/MathJax_Vector-Bold.eot');
    src /*2*/: url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/woff/MathJax_Vector-Bold.woff') format('woff'), url('https://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Vector-Bold.otf') format('opentype')
}

.wording div.example {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-11);
}

.wording div.note {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-11);
}

.wording div.example {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-9);
}

.wording div.note {
	display: block;
	margin-top: 5pt;
	margin-bottom: 5pt;
	font-size: var(--base-font-size-9);
}

.wording div.note .texttt { font-size: var(--base-font-size-9); }
.wording div.example .texttt { font-size: var(--base-font-size-9); }

.wording div.note .textsf { font-family: 'Noto Sans'; font-size: var(--base-font-size-9); }
.wording div.example .textsf { font-family: 'Noto Sans'; font-size: var(--base-font-size-9); }

.wording div.note .math { font-size: var(--base-font-size-9); }
.wording div.example .math { font-size: var(--base-font-size-9); }

.wording a.footnotenum { display: none; }
.wording div.footnote { display: none; }
.wording div.footnoteSeparator { display: none; }
.wording .footnoteref { display: none; }

.wording div.nonNormativeOnly { display: none; }


</style>
	
<!-- may.css -->
<style>
:root {
	--hana-nav-size: 300px;
	--hana-article-left-padding: 300px;
	--hana-background: white;
	--hana-foreground: black;
	--hana-accent: hsl(215, 100%, 35%);
	--hana-hsl-saturated-bright: hsl(0 100% 75%);
	--hana-hsl-saturated-bright-contrast: hsl(0 100% 0%);
	--hana-nav-hide-transform: translate(-300px, 0px);
}

@media (prefers-color-scheme: dark) {
	:root {
		--hana-background: #111;
		--hana-foreground: #DDD;
		--hana-accent: hsl(215, 50%, 73%);
		--hana-hsl-saturated-bright: hsl(0 25% 25%);
		--hana-hsl-saturated-bright-contrast: hsl(0 100% 50%);
	}
}

@media print {
	:root {
		--hana-accent: hsl(215, 100%, 23%);
	}
}

@media screen and (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}
}

@media only screen and (width >= 1000px) {
body:has(#hide.enabled) {
	--hana-article-left-padding: 0;
}
}

@media only screen and (width < 1000px) {
	body {
		font-size: 150%;
	}
}

/* derived and named colors */
:root {
	--hana-menu-background: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 3%);
	--hana-title-background: var(--hana-background);
	--hana-accent-foreground: color-mix(in lab, var(--hana-accent), var(--hana-foreground) 50%);
}

:root {
  overscroll-behavior: none;
}

body {
	overscroll-behavior: none;
	background-color: var(--hana-background);
	color: var(--hana-foreground);
	padding: 0;
	margin: 0;
	font-family: "Noto Serif", "CMU Sans Serif", "Times New Roman";
}

body::backdrop {
	background-color: var(--hana-background);
}

code {
	font-family: "Fira Code", "CMU Typewriter Text", "Times New Roman";
	font-size: 90%;
}

#hide {
	position: fixed;
	left: calc(var(--hana-nav-size) - 2em);
	bottom: 0.5em;
	cursor: pointer;
	z-index: 2000;
	transition: left 0.5s, color 0.5s, transform 0.5s ease-in-out;
	color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 80%);
	font-size: 20px;
}

@media only screen and (width >= 1000px) {
	#hide.enabled {
		left: 1em;
		transform: rotate(-180deg);
	}

	body:has(#hide.enabled) nav {
		transform: var(--hana-nav-hide-transform);
	}
}



nav {
	position: fixed;
	top: 0;
	left: 0;
	bottom: 0;
	width: var(--hana-nav-size);
	padding: 1em;
	background: var(--hana-menu-background);
	color: var(--hana-foreground);
	box-sizing: border-box;
	
	overflow-wrap: break-word;
	hyphens: auto;
	word-spacing: 0;
	font-size: 90%;
	overflow-y: scroll;
	
	h1 {
		margin-top: 0;
		margin-bottom: 0;
	}
	
	.paper-info {
		display: grid;
		grid-template-columns: auto 1fr;
		.key {
			text-align: right;
			font-weight: bold;
			padding-right: 0.5em;
		}
		padding-right: 1em;
	}
	
	#toc {
		display: grid;
		grid-template-columns: 1fr;
		padding-top: 0.5lh;
		padding-bottom: 1lh;
		h1 {
			margin-bottom: 0.5em;
		}
		ul {
			padding-left: 1em;
			list-style-type: square;
		}
		> ul {
			padding-left: 2em;
			margin: 0;
		}
		
	}
}

@media only screen and (width < 1000px) {
	:root {
		--hana-article-left-padding: 0;
		--hana-title-background: var(--hana-menu-background);
	}
	nav {
		position: static;
		width: 100vw;
		margin: 0;
	}
	#hide {
		display: none;
	}
}

@media print {
	:root {
		--hana-article-left-padding: 0;
		--hana-title-background: var(--hana-menu-background);
	}
	nav {
		position: static;
		width: 100vw;
		margin: 0;
		transform: none !important;
	}
	section > p, section > pre {
		break-inside: avoid;
	}
	#toc {
		display: none;
	}
	#hide {
		display: none;
	}
}


article {	
	color: var(--hana-foreground);
	padding: 1em;
	margin-left: var(--hana-article-left-padding);
	max-width: 100vw;
	
	p:has(+section) {
		margin-bottom: 0;
	}
	
	section {
		> *:last-child {
			margin-bottom: 0;
		}
	}
	
	.wording, pre, code {
		background: color-mix(in lab, var(--hana-accent), var(--hana-background) 98%);
		&code {
			color: var(--hana-accent-foreground);
		}
	}
	
	.wording, pre {
		padding: 1em;
		border-radius: 1em;
		> *:first-child {
			margin-top: 0
		}
		> *:last-child {
			margin-bottom: 0
		}
	}
	
	.wording pre {
		padding: 0;
	}
	
	&.transitionable {
		/*transition: margin-left 0.5s;*/
	}
	
	pre {
		tab-size: 2;
		
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap;
		overflow-wrap: anywhere;
		
		code.hljs {
			.added, .removed, .before, .after {
				line-height: 1.3;
			}
			
			font-variant-ligatures: none;
			line-height: 1.3;
			* {
				font-size-adjust: 0.5;
			}
			.hljs-keyword, .hljs-built_in, .hljs-type {
				font-weight: bold;
			}
			.hljs-string {
				font-style: italic;
				text-decoration: underline;
			}
			.hljs-comment {
				color: color-mix(in hsl, currentcolor, var(--hana-background) 50%);
			}
		}
	}
	
	p:first-child {
		margin-top: 0;
	}
	
	p {
		color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 15%);
		text-align: left;
		overflow-wrap: break-word;
		hyphens: auto;
		word-spacing: 0;
		text-wrap: pretty;
	}
	
	.before {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 0 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 0 s l);
		z-index: 10;
		padding: 0 0.5em;
	}
	.after {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 90 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 90 s l);
		z-index: 20;
		padding: 0 0.5em;
	}
	.removed, .rem {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 0 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 0 s l);
		--hana-context-decoration: hsl(from var(--hana-hsl-saturated-bright) 0 s 40);
		--hana-context-text-decoration: hsl(from var(--hana-hsl-saturated-bright) 0 s 40 / 0.75);
		text-decoration: line-through;
	}
	.added, .add, .change {
		--hana-context-background: hsl(from var(--hana-hsl-saturated-bright) 90 s l);
		--hana-context-accent: hsl(from var(--hana-hsl-saturated-bright-contrast) 90 s l);
		--hana-context-decoration: hsl(from var(--hana-hsl-saturated-bright) 90 s 40);
		--hana-context-text-decoration: hsl(from var(--hana-hsl-saturated-bright) 90 s 40 / 0.75);
	}
	.removed, .rem, .added, .add {
		&, * {
			text-decoration-thickness: 3px;
			text-decoration-color: var(--hana-context-text-decoration);
		}
	}
	.removed, .rem, .added, .add, .change {
		
	}
	.before, .after, .removed, .rem, .added, .add {
		print-color-adjust:exact;
		border: none;
		margin: 0;
		padding: 1px 0;
		background: var(--hana-context-background);
		h1, h2, h3, h4, h5, .note, .example, pre, code {
			background: inherit;
		}
		&, * {
			color: var(--hana-context-accent) !important;
		}
	}
}

body:fullscreen {
	overflow-y: scroll;
}

body:fullscreen article {
	overflow-y: scroll;
}

.added, .removed, .change {
	print-color-adjust:exact;
	&:has(&.selected-current) {
		z-index: 5006;
		position: relative;
		outline: 2px solid var(--hana-context-decoration);

		&, .added, .removed, change {
			&:not(.selected-current) {
				--hana-local-background: hsl(from var(--hana-context-background) calc(h - 15) calc(s) l);
				background: var(--hana-local-background) !important;
				outline: 1px solid var(--hana-local-background);
			}
		}
	}
}

.selected-current, .wording .texpara:has(.selected-current), .context:has(.selected-current) {
	z-index: 5005;
	position: relative;
	outline: 2px solid var(--hana-context-decoration);
	background: var(--hana-context-background);
	--special-hana: hana;
}

section:has(.selected-current) {
	& > h1 {
		z-index: 5030;
	}
	& > h2 {
		z-index: 5025;
	}
	& > h3 {
		z-index: 5020;
	}
	& > h4 {
		z-index: 5015;
	}
	& > h5 {
		z-index: 5010;
	}
}

#overlay {
	display: block;
	position: fixed;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
	z-index: 5000;
	background-color: rgb(from var(--hana-background) r g b / 0.75);
	pointer-events: none;
}

/* links are all defined here! */
a {
	color: var(--hana-accent);
	&:visited {
		color: hsl(from var(--hana-accent) calc(h - 120) s l);
	}
	&:hover {
		color: hsl(from var(--hana-accent) calc(h + 120) s l) !important;
	}
	&::after {
		margin-left: 0.2em;
		display: inline-block;
		font-size: 80%;
		width: 1em;
		height: 1em;
	}
	&:target {
		outline: none;
		&::after {
			content: "⚓︎";
		}
	}
	&[href^="https://"], &[href^="http://"] {
		&:not(&.revision):not([href^="http://eel.is"]):not([href^="https://eel.is"]):not([href^="http://github.com/Eelis/"]) {
			@media only screen {
				&::after {
					font-family: "Noto Serif", "CMU Sans Serif", "Times New Roman";
					font-size: 14px;
					content: "⎋";
					transform: scale(-1, 1);
				}
			}
		}
	}
}

section {
	position: relative;
}

h1, h2, h3, h4, h5, hr {
	word-break: keep-all;
	white-space: nowrap;
	--hana-header-color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 15%);
	--hana-header-decoration-color: color-mix(in hsl, var(--hana-foreground), var(--hana-background) 75%);
	text-decoration: none;
	margin-bottom: 0;
	margin-top: 0;
	&:not(hr) {
		padding-top: 1lh;
	}
	line-height: 30px;
	a {
		text-decoration: none;
		&, &:visited, &:hover, &:target {
			color: var(--hana-header-color) !important;
		}
	}
}

div:has(>h2) + p {
	margin-top: 0.5em;
}

hr {
	margin-top: 0.8em;
	height: 2px;
  background-color: none;
  border:none;
	border-top: 2px dotted var(--hana-header-decoration-color);
}

article {
	padding-top: 0;
}

h1#name-of-paper {
	/*position: sticky;*/
	top: 0lh;
	left: 16px;
	margin-top: 0;
	z-index: 5950;
	padding-top: 0.5lh;
	padding-bottom: 0.25lh;
}

body {
	position: relative;
}

article {
	position: relative;
	h1, h2, h3, h4, h5 {
		background-color: var(--hana-background);
		/*position: sticky;*/
		top: 0.5lh;
		z-index: 2000;
		box-shadow: 0 10px 10px var(--hana-background);
	}
	.wording {
		h1, h2, h3, h4, h5 {
			--hana-background: transparent;
			background-color: none;
			position: static;
			box-shadow: none;
		}
	}
	h2 {
		top: 1lh;
		z-index: 1900;
		padding-left: 3px;
	}
	h3 {
		top: 2.25lh;
		z-index: 1800;
		padding-left: 6px;
	}
	h4 {
		top: 3.5lh;
		z-index: 1700;
		padding-left: 9px;
	}
	h5 {
		top: 6.5lh;
		z-index: 1800;
		padding-left: 12px;
	}
}

.wording {
	h1, h2, h3, h4, h5 {
		position: static;
	}
}

@media only screen and (width < 1000px) {
	.wording {
		padding-left: 0em !important;
		padding-right: 0em !important;
	}
	body {
		overflow-x: hidden;
	}
	article {
		padding: 0 0.5em;
	}
	p {
		padding: 0 0.5em;
	}
	h1,h2,h3,h4,h5 {
		position: static !important;
		overflow-wrap: anywhere !important;
		word-break: break-word;
		hyphens: auto;
		white-space: pre-wrap;
	}
}


article section > h1, article > h1 {
	border-bottom: 2px solid var(--hana-header-decoration-color);
}

article section > h2 {
	border-bottom: 2px solid var(--hana-header-decoration-color);
}

article section > h3 {
	border-bottom: 2px dotted var(--hana-header-decoration-color);
}

article section > h4, article section > h5 {
	border-bottom: none;
}

.wording {
	padding-left: 2em;
	
	span.codeblock  {
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap !important;
		overflow-wrap: anywhere;
	}
	
	.comment {
		color: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 75%) !important;
	}
	
	.note, .example {
		background-color: rgba(from var(--hana-foreground) r g b / 3%);
		padding: 0 0.3em;
		margin: 0.3em;
		border-radius: 0.3em;
		font-size: 95% !important;
		*:not(.note):not(.example) {
			background: none;
		}
	}
	
	code {
		text-align: left;
		white-space: pre-wrap;
	  word-break: break-all;
		overflow-x: wrap;
		overflow-wrap: anywhere;
		
		em {
			& * {
				font-style: italic;
				font-weight: normal !important;
			}
		}
	}
}

code, .wording .codeblock, .wording span.texttt, .wording span.terminal, .wording span.noncxxterminal .wording span.tcode, .wording span.mathtt, .wording div.footnote span.texttt, .wording span.tcode_in_codeblock, .wording .outputblock, .wording code.itemdeclcode, .wording span.literalterminal, .wording .MJXc-TeX-type-R {
	font-family: "Fira Code", "Noto Sans Mono", monospace !important;
	font-variant-ligatures: no-contextual;
	line-height: 1.3;
	* {
		font-size-adjust: 0.5;
	}
}

.hana_wording  {
	pre {
		padding-top: 1lh !important;
	}
	h2 {
    line-height: 1 !important;
    font-size: var(--base-font-size-16) !important;
    margin-top: 10pt !important;
    margin-bottom: 10pt !important;
	}
	h3 {
    line-height: 1 !important;
    margin-top: 10pt !important;
    margin-bottom: 10pt !important;
	}
}

@media screen {
	#draft-warning {
		position: fixed;
		bottom: 0;
		right: 0;
		background: red;
		font-family: "Fira Code", "Noto Sans Mono", monospace !important;
		font-size: 150%;
		padding: 8px 100px;
		text-transform: uppercase;
		transform: translateY(-30px) translateX(80px) rotate(-45deg);
		z-index: 50000;
		color: white;
	}
}
@media print {
	#draft-warning {
		display: none;
	}
}

</style>
</head>
<body>

<!-- navigation sidebar -->
	
<nav>
<div class="paper-info">
	<span class="key">Number:</span><span>P3125R4</span>
	<span class="key">Date:</span><span><time>2025-05-19</time></span>
	<span class="key">Audience:</span><span><a href="mailto:Library&nbsp;Evolution (YOU-NEED-JAVASCRIPT-ENABLED) #TGlicmFyeSZuYnNwO0V2b2x1dGlvbiA8bGliLWV4dEBsaXN0cy5pc29jcHAub3JnPj9zdWJqZWN0PVAzMTI1UjQ6IGNvbnN0ZXhwciBwb2ludGVyIHRhZ2dpbmc=" onclick="return send_email(this)">Library&nbsp;Evolution</a></span>
	<span class="key">Author:</span><span><a href="mailto:hana dusikova (YOU-NEED-JAVASCRIPT-ENABLED) #SGFuYStEdXMlQzMlQURrb3YlQzMlQTEgPGhhbmlja2FAaGFuaWNrYS5uZXQ+P3N1YmplY3Q9UDMxMjVSNDogY29uc3RleHByIHBvaW50ZXIgdGFnZ2luZw==" onclick="return send_email(this)">Hana Dusíková</a><span>
</div>
<hr/>
<div id="toc">
<ul>
<li><a href="#acknowledgement">Acknowledgement</a></li>
<li><a href="#revision-history">Revision history</a></li>
<li><a href="#introduction-and-motivation">Introduction and motivation</a></li>
<ul>
<li><a href="#use-cases">Use cases</a></li>
<li><a href="#safety">Safety</a></li>
<ul>
<li><a href="#unsafe-operations">Unsafe operations</a></li>
</ul>
<li><a href="#examples">Examples</a></li>
<ul>
<li><a href="#hamt-early-leaves">HAMT early leaves</a></li>
<li><a href="#smart-%28non-%29owning-pointer">Smart (non-)owning pointer</a></li>
<li><a href="#llvm%27s-l-value">LLVM's L-value</a></li>
</ul>
</ul>
<li><a href="#implementation-experience">Implementation experience</a></li>
<ul>
<li><a href="#implementation-in-the-library">Implementation in the library</a></li>
<ul>
<li><a href="#accessing-raw-tagged-pointers">Accessing raw tagged pointers</a></li>
</ul>
<li><a href="#implementation-in-the-compiler">Implementation in the compiler</a></li>
<ul>
<li><a href="#compiler-builtins">Compiler builtins</a></li>
<li><a href="#constant-evaluation">Constant evaluation</a></li>
<li><a href="#pointer-provenance-and-optimization">Pointer provenance and optimization</a></li>
<li><a href="#alternative-constexpr-compatible-implementation">Alternative constexpr compatible implementation</a></li>
</ul>
</ul>
<li><a href="#design">Design</a></li>
<ul>
<li><a href="#preconditions-and-eligibility-of-constructors">Preconditions and eligibility of constructors</a></li>
<li><a href="#representation-of-tag-value">Representation of tag value</a></li>
<li><a href="#tuple-protocol">Tuple protocol</a></li>
</ul>
<li><a href="#things-it%27s-not-doing-and-why">Things it's not doing and why</a></li>
<li><a href="#impact-on-existing-code">Impact on existing code</a></li>
<li><a href="#proposed-changes-to-wording">Proposed changes to wording</a></li>
<ul>
<li><a href="#feature-test-macro">Feature test macro</a></li>
</ul>
</ul></div>
</nav>
<div id="hide">◀︎</div>
<!-- main content -->
<article spellcheck="true">
	<h1 id="name-of-paper">constexpr pointer tagging</h1>
	<p>This paper proposes a new library non-owning pointer and value pair which has ability to store small amount of information in a <em>tag</em> in alignment low-bits. This functionality is also usable in <code>constexpr</code> environment. It's meant to be a building tool to build more advanced data-structures and also last requirement for <code>atomic&lt;std::shared_ptr&lt;T&gt;&gt;</code> to be constexpr.</p>
	<section data-related="acknowledgement"><h2><a href="#acknowledgement" id="acknowledgement">Acknowledgement</a></h2>	<p>I want to thank to everyone who helped me by reviewing this paper. I want to thank especially Tomasz Kamińsky who made the wording actually make sense.</p>
	</section><section data-related="revision-history"><h2><a href="#revision-history" id="revision-history">Revision history</a></h2>	<ul>
		<li><a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3125r3.html">R3</a>&#x2005;→&#x2005;R4: changes requested by LEWG (removed <code>nullptr_t</code> constructor, <a href="#support-for-void">added support for <code>void *</code></a>, <a href="#pointer-not-pointee">first template argument is now pointer and not pointee</a>, added <a href="#pointer-tag-trait"><code>pointer_tag_trait</code> to inspect available bits inside pointers</a>, added <a href="#tuple-like-interface"><code>tuple_size</code>, <code>tuple_element</code>, and <code>get&lt;N&gt;(pointer_tag_ptr)</code></a>)</li>
		<li><a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3125r2.html">R2</a>&#x2005;→&#x2005;<a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3125r3.html">R3</a>: polishing design and <a class="revision" href="#proposed-changes-to-wording">added wording</a></li>
		<li><a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3125r1.html">R1</a>&#x2005;→&#x2005;<a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3125r2.html">R2</a>: simplifying design by removing schemas and the heavy interface, massive simplification as discussed in SG1 (<code>pointer_tag_pair</code>, required <code>sizeof(pointer_tag_pair) == sizeof(T*)</code>)</li>
		<li><a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3125r0.pdf">R0</a>&#x2005;→&#x2005;<a class="revision" href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3125r1.html">R1</a>: proposing and explaining design based on existing implementation</li>
	</ul>
	</section><section data-related="introduction-and-motivation"><h2><a href="#introduction-and-motivation" id="introduction-and-motivation">Introduction and motivation</a></h2>	<p>Pointer tagging is widely known and used technique (<a href="https://takenobu-hs.github.io/downloads/haskell_ghc_illustrated.pdf">Glasgow Haskell Compiler</a>, LLVM's <code><a href="https://github.com/llvm/llvm-project/blob/8e5aa538caccef167e8096b2173fdaf2be9cc129/llvm/include/llvm/ADT/PointerIntPair.h#L80">PointerIntPair</a></code>, <code><a href="https://github.com/llvm/llvm-project/blob/8e5aa538caccef167e8096b2173fdaf2be9cc129/llvm/include/llvm/ADT/PointerUnion.h#L112">PointerUnion</a></code>, <a href="https://blog.codingconfessions.com/p/cpython-garbage-collection-internals">CPython's garbage collector</a>, <a href="https://alwaysprocessing.blog/2023/03/19/objc-tagged-ptr">Objective C</a> / Swift, Chrome's <a href="https://v8.dev/blog/pointer-compression">V8 JavaScript engine</a>, <a href="https://www.gap-system.org">GAP</a>, <a href="https://ocaml.org/docs/memory-representation#distinguishing-integers-and-pointers-at-runtime">OCaml</a>, <a href="https://pbr-book.org/4ed/Utilities/Containers_and_Memory_Management#TaggedPointers">PBRT</a>). All major CPU vendors provides mechanism for pointer tagging (Intel's LAM <a href="https://cdrdv2-public.intel.com/835759/325462-sdm-vol-1-2abcd-3abcd-4.pdf">linear address masking</a>, AMD's <a href="https://www.amd.com/content/dam/amd/en/documents/processor-tech-docs/programmer-references/24593.pdf">Upper Address Ignore</a>, ARM's TBI <a href="https://en.wikichip.org/wiki/arm/tbi">top byte ignore</a> and MTE <a href="https://en.wikichip.org/wiki/arm/mte">memory tagging extension</a>). All widely used 64 bit platforms are <a href="https://muxup.com/2023q4/storing-data-in-pointers">not using more than 48 or 49 bits of the pointers</a>.</p>
	<p>This functionality widely supported can't be expressed in a standard conforming way.</p>
	<p><a href="https://doc.rust-lang.org/std/primitive.pointer.html#examples-9">Rust</a>, <a href="https://dlang.org/library/std/bitmanip/tagged_pointer.html">Dlang</a>, or <a href="https://zig.news/orgold/type-safe-tagged-pointers-with-comptime-ghi">Zig</a> has an interface for pointer tagging. This is demonstrating demand for the feature and C++ should have it too and it should also work in <code>constexpr</code>.</p>
	
<!-- image.css (paper specific) -->
<style>
@media (prefers-color-scheme: dark) {
	svg {
		
	}
}

@media (prefers-color-scheme: light) {
	svg {
		
	}
}

svg {
	max-width: 55em;
}

svg g#outside-text text {
	font-family: "Noto Serif", "CMU Sans Serif", "Times New Roman";
	fill: var(--hana-foreground);
}

svg g#arrows {
	line, polygon {
		stroke: var(--hana-foreground);
	}
}

svg g#items rect {
	stroke: var(--hana-foreground);
	&[fill="#fff"] {
		fill: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 10%);
	}
	&[fill="#e6e7e8"], &[fill="#bcbec0"] {
		fill: color-mix(in hsl, var(--hana-background), var(--hana-foreground) 50%);
	}
	&[fill="#f285b5"] { /* arm */
		fill: hsl(from var(--hana-hsl-saturated-bright) 0 s l);
	}
	&[fill="#79c2e2"] { /* intel u48 */
		fill: hsl(from var(--hana-hsl-saturated-bright) 45 s l);
	}
	&[fill="#edde5d"] { /* intel u57 */
		fill: hsl(from var(--hana-hsl-saturated-bright) -120 s l);
	}
	&[fill="#8dc63f"] { /* low bits */
		fill: hsl(from var(--hana-hsl-saturated-bright) 120 s l);
	}
}
</style>
	<div class="svg"><?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 760.96 125.86">
  <g id="outside-text">
    <text transform="translate(95.72 102.32)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12">Intel's LAM U57</text>
    <text transform="translate(174.23 87.57)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12">Intel’s LAM U48</text>
    <text transform="translate(95.55 72.82)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12">ARM’s top byte ignore</text>
    <text transform="translate(544.97 31.68)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12">low bits</text>
    <text transform="translate(648.1 71.01)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12"><tspan x="0" y="0">bits with </tspan><tspan x="0" y="14.4">zeros due</tspan><tspan x="0" y="28.8">pointer alignment</tspan><tspan x="0" y="43.2">(proposed)</tspan></text>
    <text transform="translate(368.71 10.41)" fill="#231f20" font-family="Helvetica, Helvetica" font-size="12"><tspan x="0" y="0">48 bit pointer</tspan></text>
  </g>
  <g id="arrows">
    <line x1="641.45" y1="117.08" x2="641.45" fill="none" stroke="#a7a9ac" stroke-linecap="square" stroke-miterlimit="10"/>
    <g>
      <line x1="484.07" y1="36.65" x2="635.48" y2="36.65" fill="none" stroke="#231f20" stroke-miterlimit="10"/>
      <polygon points="632.67 40.35 634.24 36.65 632.67 32.94 641.45 36.65 632.67 40.35" fill="#231f20"/>
    </g>
    <g>
      <line x1="175.29" y1="17.16" x2="635.48" y2="17.16" fill="none" stroke="#231f20" stroke-miterlimit="10"/>
      <polygon points="178.09 20.86 176.52 17.16 178.09 13.46 169.32 17.16 178.09 20.86" fill="#231f20"/>
      <polygon points="632.67 20.86 634.24 17.16 632.67 13.46 641.45 17.16 632.67 20.86" fill="#231f20"/>
    </g>
    <line x1="169.32" x2="169.32" y2="58.06" fill="none" stroke="#a7a9ac" stroke-linecap="square" stroke-miterlimit="10"/>
  </g>
  <g id="items">
    <rect x="11.94" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="21.78" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="31.61" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="41.45" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="51.28" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="61.12" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="70.96" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="80.79" y="48.23" width="9.84" height="9.84" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="90.63" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="100.46" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="110.3" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="120.14" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="129.97" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="139.81" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="149.64" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="159.48" y="48.23" width="9.84" height="9.84" fill="#e6e7e8" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="169.32" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="179.15" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="188.99" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="198.82" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="208.66" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="218.5" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="228.33" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="238.17" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="248.01" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="257.84" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="267.68" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="277.51" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="287.35" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="297.19" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="307.02" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="316.86" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="326.69" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="336.53" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="346.37" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="356.2" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="366.04" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="375.87" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="385.71" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="395.55" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="405.38" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="415.22" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="425.05" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="434.89" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="444.73" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="454.56" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="464.4" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="474.23" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="484.07" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="493.91" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="503.74" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="513.58" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="523.42" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="533.25" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="543.09" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="552.92" y="46.36" width="9.84" height="11.7" fill="#fff" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="562.76" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="572.6" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="582.43" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="592.27" y="46.36" width="9.84" height="11.7" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="602.1" y="48.23" width="9.84" height="9.84" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="611.94" y="48.23" width="9.84" height="9.84" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="621.78" y="48.23" width="9.84" height="9.84" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="631.61" y="48.23" width="9.84" height="9.84" fill="#bcbec0" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="611.94" y="77.73" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="621.78" y="77.73" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="631.61" y="77.73" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="621.78" y="92.49" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="631.61" y="92.49" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="631.61" y="107.24" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="611.94" y="62.98" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="621.78" y="62.98" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="631.61" y="62.98" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="602.1" y="62.98" width="9.84" height="9.84" fill="#8dc63f" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="11.94" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="21.78" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="31.61" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="41.45" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="51.28" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="61.12" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="70.96" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="80.79" y="62.98" width="9.84" height="9.84" fill="#f285b5" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="90.63" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="100.46" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="110.3" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="120.14" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="129.97" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="139.81" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="149.64" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="159.48" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="21.78" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="31.61" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="41.45" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="51.28" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="61.12" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="70.96" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="80.79" y="77.73" width="9.84" height="9.84" fill="#79c2e2" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="21.78" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="31.61" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="41.45" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="51.28" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="61.12" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="70.96" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
    <rect x="80.79" y="92.49" width="9.84" height="9.84" fill="#edde5d" stroke="#231f20" stroke-miterlimit="10"/>
  </g>
</svg></div>
	<p>Generally programmer can consider low-bits used for alignment to be safely used for storing an information. Upper bits are available on different platforms under different conditions (runtime processor setting, CPU generation, ...). This proposal only proposes interface to accessing low bits for storing // reading a tag value, not observing bits of a pointer.</p>
	<p>This proposal doesn't propose accessing any other bits other than low-bits which are known to be zero due alignment. <a href="https://github.com/cplusplus/papers/issues/1903#issuecomment-2488661934">SG1 doesn't want</a> to standardize access to high-bits as it's considered dangerous and non-portable. And can limit future development of security features in OS and CPUs for which high-bits are used.</p>
	<section data-related="use-cases"><h3><a href="#use-cases" id="use-cases">Use cases</a></h3>	<p>There are three basic use-cases of pointer tagging:</p>
	<ul>
		<li>marking pointer with an information (in allocators, used as a tiny refcount, or marking source of the pointer)</li>
		<li>pointee polymorphism (usually in data structures, eg. in trees: next node can be an internal node or a leaf)</li>
		<li>in-place polymorphism (similarly as variant, some bits stores an information about rest of payload, it can be a pointer, a number, a float, a small string, ...)</li>
	</ul>
  <p>This paper aims to solve only first two use-cases.</p>
	</section><section data-related="safety"><h3><a href="#safety" id="safety">Safety</a></h3>	<p>Pointer tagging can be currently implemented in C++ only with <code>reinterpret_cast</code> and bit manipulating with shifts / bitand / bitor and this approach is prone to be unsafe and hard to debug as it's not expressed clearly in code what is the right intention, so compiler can't even diagnose incompatibility between encode/decode. By giving a name to this tool it allows programmer to express intent clearly and compiler to optimize and diagnose problems properly.</p>
	<p>Preconditions and mandates of proposed <code>std::pointer_tag_pair</code> makes it unlike to use it unsafely as potentially dangerous operations (<code>std::pointer_tag_pair&lt;Pointee, Tag, Bits&gt;::from_tagged(<em>pointer</em>)</code> and <code>std::pointer_tag_pair&lt;Pointee, Tag, Bits&gt;::template from_overaligned&lt;PromisedAlignment&gt;(<em>pointer</em>)</code>) are verbose and visible.</p>
	<section data-related="unsafe-operations"><h4><a href="#unsafe-operations" id="unsafe-operations">Unsafe operations</a></h4>	<p>Two mentioned functions are provided so user can explicitly provide over-aligned pointer which would otherwise won't be compatible with number of requested bits or interact with existing functionality for pointer tagging (which will allow gradual adoption of the feature and replace old code).</p>
	</section></section><section data-related="examples"><h3><a href="#examples" id="examples">Examples</a></h3>	<section data-related="hamt-early-leaves"><h4><a href="#hamt-early-leaves" id="hamt-early-leaves">HAMT early leaves</a></h4>	<p>Following example is a recursive search implementation for a <a href="https://en.wikipedia.org/wiki/Hash_array_mapped_trie">HAMT (hash-array-mapped-trie)</a> data structure. Where a tag value indicates leaf node.</p>
	<pre><code class="language-cpp">// requesting only 1 bit of information
using hamt_node_pointer = std::pointer_tag_pair&lt;const void, bool, 1&gt;;
static_assert(sizeof(hamt_node_pointer) == sizeof(void *));

constexpr const T * find_value_in_hamt(hamt_node_pointer tptr, uint32_t hash) {
	if (tptr == nullptr) // checks only pointer part
		return nullptr;
	
	if (tptr.tag()) // we found leaf node, tag is boolean as specified
		return *static_cast&lt;const T *&gt;(tptr.pointer());
	
	const auto * node = static_cast&lt;const internal_node *&gt;(tptr.pointer());
	const auto next_node = node[hash & 0b1111u];
	
	return find_value_in_hamt(next_node, hash >> 4); // recursive descend
}</code></pre>
</section><section data-related="smart-%28non-%29owning-pointer"><h4><a href="#smart-%28non-%29owning-pointer" id="smart-%28non-%29owning-pointer">Smart (non-)owning pointer</a></h4>  <p>This example shows <code>maybe_owning_ptr</code> type which can be both a reference or an owner:</p>
  <pre><code class="language-cpp">template &lt;typename T&gt; class maybe_owning_ptr {
  enum class ownership: unsigned {
    reference,
    owning,
  };
  
  std::pointer_tag_pair&lt;T, ownership, 1&gt; _ptr;
public:
  constexpr maybe_owning_ptr(T* && pointer) noexcept: _ptr{pointer, ownership::owning} { }
  constexpr maybe_owning_ptr(T & ref) noexcept: _ptr{&ref, ownership::reference} { }
  
  constexpr decltype(auto) operator*() const noexcept {
    return *_ptr.pointer();
  }
  
  constexpr T * operator->() const noexcept {
    return _ptr.pointer();
  }
  
  constexpr ~maybe_owning_ptr() noexcept {
    if (_ptr.tag() == ownership::owning) {
      delete _ptr.pointer();
    }
  }
};

static_assert(sizeof(maybe_owning_ptr&lt;int&gt;) == sizeof(int *));</code></pre>
</section><section data-related="llvm%27s-l-value"><h4><a href="#llvm%27s-l-value" id="llvm%27s-l-value">LLVM's L-value</a></h4><p>Following code is simplification of LLVM's representation of <a href="https://github.com/llvm/llvm-project/blob/171d3edd0507422f64cc11b33dac7b7f2b703f76/clang/include/clang/AST/APValue.h#L146-L149">pointer/reference type</a> which is implemented with LLVM's <code>PointerIntPair</code> and is inside constant evaluator. This type holds subnodes of different kind: pointer to local/static variable, dynamic allocation, type info pointer, result of temporary.</p>
<pre><code class="language-cpp">struct LValueBase {
	using PtrTy = llvm::PointerUnion&lt;const ValueDecl *, 
                                    const Expr *,
                                    TypeInfoLValue,
                                    DynamicAllocLValue&gt;;

	struct PathEntry {
		uint64_t value;
	};
	
	using PathTy = std::vector&lt;PathEntry&gt;;
	
	PtrTy Location;
	PathEntry SubObjectPath;
};

APValue DereferencePointer(EvalInfo &amp; Context, const LValueBase & Base) {
	auto & object = Context.Visit(Base.Location);
	return object.NavigateToSuboject(Base.SubObjectPath);
}</code></pre>
	</section></section></section><section data-related="implementation-experience"><h2><a href="#implementation-experience" id="implementation-experience">Implementation experience</a></h2>	<p>Old version of this proposal has been implemented within libc++ &amp; clang and it is accessible on <a href="https://github.com/llvm/llvm-project/pull/111861">github</a> and <a href="https://compiler-explorer.com/z/Y884arzjd">compiler explorer</a>. This functionality can't be implemented as a pure library (<code>reinterpret_cast</code> is not allowed during constant evaluation) and needs compiler support in some form.</p> 
	<section data-related="implementation-in-the-library"><h3><a href="#implementation-in-the-library" id="implementation-in-the-library">Implementation in the library</a></h3>	<p>Library is providing a special pair-like type containing pointer and small tag type, and user requested number of bits. The number of bits is by default deduced by default alignment of requested pointee type. Requesting more bits than alignment will disable normal constructor, and force user to use <code>::from_overaligned</code> function as overalignment is not part of C++'s type system.</p>
	<p>In terms of library design there is nothing surprising, and it's pretty straightforward wrapper which encode and decode tagged pointer on its boundaries and provides basic pointer functionality.</p>
	<section data-related="accessing-raw-tagged-pointers"><h4><a href="#accessing-raw-tagged-pointers" id="accessing-raw-tagged-pointers">Accessing raw tagged pointers</a></h4>	<p>The pointer int pair has support to access <em>raw</em> tagged pointer. Which is a pointer which can't be dereferenced or otherwise manipulated with, it's an opaque value usable only with legacy tagging interface or it can be used to construct <code>pointer_tag_pair</code> back from it. Existence of this interface allows ability to store such pointers in existing interfaces (atomic, other smart pointers). Question is if it should be <code>uintptr_t</code> or <code>void*</code>. I prefer <code>void*</code> as roundtriping thru an integer looses information about provenance and can disable some optimization.</p>
	</section></section><section data-related="implementation-in-the-compiler"><h3><a href="#implementation-in-the-compiler" id="implementation-in-the-compiler">Implementation in the compiler</a></h3>	<p>The implementation is providing builtins to manipulating raw pointers and isn't meant to be used by end-users, only to allow this library functionality.</p>
	<section data-related="compiler-builtins"><h4><a href="#compiler-builtins" id="compiler-builtins">Compiler builtins</a></h4>	<p>Implementation needs to manipulate pointers without casting them to integers and back. To do so the provided set of builtins is designed to store/load a value (with size of few bits) into/from unimportant/unused bits of a pointer without observing actual pointer representation.</p>
	</section><section data-related="constant-evaluation"><h4><a href="#constant-evaluation" id="constant-evaluation">Constant evaluation</a></h4>	<p>With these builtins it's trivial to implement semantically identical behaviour for the constant evaluation. In case of my implementation, pointers in clang are not represented as addresses but as symbols (original AST variable, allocation, static object + path to subobject, its provenance) and there is no address to manipulate. Actual tag value in such "pointer" is then stored in a metadata of the pointer itself and builtins only provide access to it. Technically such storage can provide more bits than pointer "size", but there are internal checks which make sure it allows only bits which would be accessible in runtime based on alignment of individual pointer.</p>
	<p>Any attempt to deference or otherwise manipulate such pointer, which would be unsafe in runtime, is detected and reported by the interpreter. Only the provided builtins can recover original pointer and tag value.</p>
	</section><section data-related="pointer-provenance-and-optimization"><h4><a href="#pointer-provenance-and-optimization" id="pointer-provenance-and-optimization">Pointer provenance and optimization</a></h4>	<p>Easiest way to implement builtins for pointer tagging is to do the same thing <code>reinterpret_cast</code> is doing, which was my first implementation approach. But this approach leads to loosing pointer's provenance and compiler loosing information which otherwise should be accessible for optimizer to use.</p>
	<p>For unmasking there is already <code>ptr.mask</code> LLVM's builtin, but there is no similar intrinsic to do the tagging. Hence the builtins needs to interact with backend and be implemented with a low level backend intrinsic to do the right thing. This shows how actually unimplementable pointer tagging is in existing language.</p>
	</section><section data-related="alternative-constexpr-compatible-implementation"><h4><a href="#alternative-constexpr-compatible-implementation" id="alternative-constexpr-compatible-implementation">Alternative constexpr compatible implementation</a></h4>	<p>Alternative way to implement <code>constexpr</code> support (for compiler which don't have heavy pointer representation in their interprets) is inserting a hidden intermediate object holding the metadata and pointer to original object. This allows exactly same semantic as the metadata approach, and can be completely implemented in library using <code>if consteval</code>, but it will need allocation during constant evaluation.</p>
	</section></section></section><section data-related="design"><h2><a href="#design" id="design">Design</a></h2>	<p>The <code>std::pointer_int_pair</code> is simple pair-like template providing only necessory interface and is not meant to provide heavy interface as it's preferable to not hide pointer tagging / untagging from users. This is mean to be a low-level facility. Main requirement on the type is it must be always same size as stored pointer and not more.</p>
	<p>This chapter was partially removed because it was too similar to wording, you can find it in <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3125r3.html#design">previous version of paper</a>.</p>
<section data-related="preconditions-and-eligibility-of-constructors"><h3><a href="#preconditions-and-eligibility-of-constructors" id="preconditions-and-eligibility-of-constructors">Preconditions and eligibility of constructors</a></h3>  <p>Constructor taking a pointer and tag value is only available if alignment of the pointee type is enough to store requested number of bits.</p>
	<p>Both the constructor and <code>::from_overaligned</code> function have preconditions checking if pointer is aligned enough as expected (in the constructor) or promised overaligned (in the <code>::from_overaligned</code> function). In addition to this there is a precondition to make sure value of tag type is representible with <code>RequestedBits</code>.</p>
</section><section data-related="representation-of-tag-value"><h3><a href="#representation-of-tag-value" id="representation-of-tag-value">Representation of tag value</a></h3>	<p>Tag value can only be unsigned integral type or an enum type with underlying unsigned integral type. The value is converted to the underlying or kept original unsigned integral type and then it is bit masked with mask based on <em>BitsRequested</em> bits (<code>1u &lt;&lt; BitsRequested - 1u</code>).</p>
	<p>It's precondition failure for the value after this conversion different than original value. An attempt was made to support signed type, but unfortunetely storing unrepresentable value into a bitfield is implementation specific. And this can be added later as extension to current design.</p>
</section><section data-related="tuple-protocol"><h3><a href="#tuple-protocol" id="tuple-protocol">Tuple protocol</a></h3>	<p><code>pointer_tag_pair</code> supports being destructured, but it doesn't model <code><em>tuple-like</em></code> (as it would open whole can of worms, as told by STL). But following code should work:</p>
	<pre><code class="language-cpp">auto [ptr, tag] = a_pointer_tag_pair;</code></pre>
</section></section><section data-related="things-it%27s-not-doing-and-why"><h2><a href="#things-it%27s-not-doing-and-why" id="things-it%27s-not-doing-and-why">Things it's not doing and why</a></h2><ul>
	<li><em>modeling pointer</em> — this is not a pointer type, access to the pointer should be explicitly visible,</li>
	<li><em>convertible to bool</em> — it's not sure if it means <code>.pointer() == nullptr</code> or also <code>.tag() == 0</code>,</li>
	<li><em>manage lifetime</em> — this is not a owning pointer, it's a tool to build one,</li>
	<li><em>using other than non-alignment bits</em> — these are not portable and are subject of being enabled/disabled as an OS setting, this would create at best ABI problems,</li>
	<li><em>changing size based on bits requested</em> — intention of this type to be same size of pointer, not be generic pair of pointer and any value,</li>
	<li><em>supporting function pointers</em> — these doesn't need to be real pointer, but handlers, and can even have bigger size than normal pointer.</li>
	<li><em>supporting signed tag types</em> — it's tricky and using bitfield is implementation specific.</li>
</ul>
</section><section data-related="impact-on-existing-code"><h2><a href="#impact-on-existing-code" id="impact-on-existing-code">Impact on existing code</a></h2>	<p>None, this is purely an API extension. It allows to express semantic clearly for a compiler instead of using an unsafe <code>reinterpret_cast</code> based techniques. Integral part of the proposed design is ability to interact with such existing code and migrate away from it.</p>

</section><section data-related="proposed-changes-to-wording"><h2><a href="#proposed-changes-to-wording" id="proposed-changes-to-wording">Proposed changes to wording</a></h2>	
<!-- mem.html (wording) -->
<div class="wording">
<div class="hana_wording">
<h1><a class='secnum' style='min-width:50pt'>20</a> Memory management library <a class='abbr_ref' href='./#mem'>[mem]</a></h1>

<div id='general' class='section'>
  
<h2><a class='secnum' href='#general' style='min-width:65pt'>20.1</a> General <a class='abbr_ref' href='mem.general'>[mem.general]</a></h2>

<div class='para' id='general-1'>
  <div class='marginalizedparent'><a class='marginalized' href='#general-1'>1</a></div>
  <div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/eb3b44202e7ac0c1ade1d69df3adba5fe496b94b/source/memory.tex#L6'>#</a></div>

<div class='texpara'><div id='general-1.sentence-1' class='sentence'>This Clause describes components for memory management<a class='hidden_link' href='#general-1.sentence-1'>.</a></div></div>

<div class='para' id='general-2'><div class='marginalizedparent'><a class='marginalized' href='#general-2'>2</a></div><div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/eb3b44202e7ac0c1ade1d69df3adba5fe496b94b/source/memory.tex#L9'>#</a></div>
<div class='texpara'><div id='general-2.sentence-1' class='sentence'>The following subclauses describe general memory management facilities,
smart pointers, <span class="added">pointer tagging, </span>memory resources, and scoped allocators,
as summarized in Table <a href='#tab:mem.summary' title='Table 47: Memory management library summary'>47</a><a class='hidden_link' href='#general-2.sentence-1'>.</a></div></div></div>

<div class='texpara'>
	
<div class='numberedTable' id='tab:mem.summary'>Table <a href='#tab:mem.summary'>47</a> &mdash; Memory management library summary&emsp;<a href='./tab:mem.summary'>[tab:mem.summary]</a><br>
	
<table >
	<tr id='tab:mem.summary-row-1' class='rowsep'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#tab:mem.summary-row-1'>🔗</a></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-1-column-2-sentence-1' class='sentence'><b>Subclause</b></div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-1-column-3-sentence-1' class='sentence'><b>Header</b></div></div></td></tr>
	<tr id='tab:mem.summary-row-2' class='capsep'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#tab:mem.summary-row-2'>🔗</a></div><div class='texpara'><div id='tab:mem.summary-row-2-column-1-sentence-1' class='sentence'><a href='#memory' title='20.2&emsp;Memory'>[memory]</a></div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-2-column-2-sentence-1' class='sentence'>Memory</div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-2-column-3-sentence-1' class='sentence'><span class='texttt'><span class='anglebracket'>&lt;</span>cstdlib<span class='anglebracket'>&gt;</span></span>, <span class='texttt'><span class='anglebracket'>&lt;</span>memory<span class='anglebracket'>&gt;</span></span></div></div></td></tr>
	<tr class='rowsep'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#'>🔗</a></div><div class='texpara'><div id='tab:mem.summary-row-3-column-1-sentence-1' class='sentence'><a href='#smartptr' title='20.3&emsp;Smart pointers'>[smartptr]</a></div></div></td><td class='left'><div class='texpara'><div class='sentence'>Smart pointers</div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-3-column-3-sentence-1' class='sentence'><span class='texttt'><span class='anglebracket'>&lt;</span>memory<span class='anglebracket'>&gt;</span></span></div></div></td></tr>
		
	<tr id='tab:mem.summary-row-3' class='rowsep added'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#tab:mem.summary-row-3'>🔗</a></div><div class='texpara'><div class='sentence'><a href='#smartptr' title='?.?&emsp;Pointer tag pair'>[ptrtag]</a></div></div></td><td class='left'><div class='texpara'><div class='sentence'>Pointer tagging</div></div></td><td class='left'><div class='texpara'><div class='sentence'><span class='texttt'><span class='anglebracket'>&lt;</span>memory<span class='anglebracket'>&gt;</span></span></div></div></td></tr>
		
	<tr id='tab:mem.summary-row-4' class='rowsep'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#tab:mem.summary-row-4'>🔗</a></div><div class='texpara'><div id='tab:mem.summary-row-4-column-1-sentence-1' class='sentence'><a href='#res' title='20.4&emsp;Memory resources'>[mem.<span class='shy'></span>res]</a></div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-4-column-2-sentence-1' class='sentence'>Memory resources</div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-4-column-3-sentence-1' class='sentence'><span class='texttt'><span class='anglebracket'>&lt;</span>memory_<span class='shy'></span>resource<span class='anglebracket'>&gt;</span></span></div></div></td></tr>
	<tr id='tab:mem.summary-row-5' class='rowsep'><td class='left'><div class='marginalizedparent'><a class='itemDeclLink' href='#tab:mem.summary-row-5'>🔗</a></div><div class='texpara'><div id='tab:mem.summary-row-5-column-1-sentence-1' class='sentence'><a href='#allocator.adaptor' title='20.5&emsp;Class template scoped_&shy;allocator_&shy;adaptor'>[allocator.<span class='shy'></span>adaptor]</a></div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-5-column-2-sentence-1' class='sentence'>Scoped allocators</div></div></td><td class='left'><div class='texpara'><div id='tab:mem.summary-row-5-column-3-sentence-1' class='sentence'><span class='texttt'><span class='anglebracket'>&lt;</span>scoped_<span class='shy'></span>allocator<span class='anglebracket'>&gt;</span></span></div></div></td></tr>

</table>

</div>
	
</div>

</div>

<div id='memory' class='section'>
<h2 ><a class='secnum' href='#memory' style='min-width:65pt'>20.2</a> Memory <a class='abbr_ref' href='memory'>[memory]</a></h2>

<div id='memory.syn' class='section'><h3 ><a class='secnum' href='#memory.syn' style='min-width:80pt'>20.2.2</a> Header <span class='texttt'>&lt;memory&gt;</span> synopsis <a class='abbr_ref' href='memory.syn'>[memory.syn]</a></h3><div class='para' id='memory.syn-1'><div class='marginalizedparent'><a class='marginalized' href='#memory.syn-1'>1</a></div><div class='sourceLinkParent'><a class='sourceLink' href='http://github.com/Eelis/draft/tree/eb3b44202e7ac0c1ade1d69df3adba5fe496b94b/source/memory.tex#L32'>#</a></div><div class='texpara'><div id='memory.syn-1.sentence-1' class='sentence'>The header <span id='header:<memory>'><span class='texttt'><span class='anglebracket'>&lt;</span>memory<span class='anglebracket'>&gt;</span></span></span> defines several types and function templates that
describe properties of pointers and pointer-like types, manage memory
for containers and other template types, destroy objects, and
construct objects in
uninitialized memory
buffers (<a href='#pointer.traits' title='20.2.3&emsp;Pointer traits'>[pointer.<span class='shy'></span>traits]</a>–<a href='#specialized.addressof' title='20.2.11&emsp;addressof'>[specialized.<span class='shy'></span>addressof]</a> and <a href='specialized.algorithms' title='26.11&emsp;Specialized &lt;memory&gt; algorithms'>[specialized.<span class='shy'></span>algorithms]</a>)<a class='hidden_link' href='#memory.syn-1.sentence-1'>.</a></div> 
  
<div class='sentence added'>The header also defines class templates <span class='textt'>pointer_tag_traits</span> and <span class='textt'>pointer_tag_pair</span> to support storing additional information in unused bits of pointers. Selection of the bits is implementation specific and the size of the pointer wrapping object is the same as the size of the original pointer.</div>
  
<div id='memory.syn-1.sentence-2' class='sentence'>The header also defines the templates
<span class='texttt'>unique_<span class='shy'></span>ptr</span>, <span class='texttt'>shared_<span class='shy'></span>ptr</span>, <span class='texttt'>weak_<span class='shy'></span>ptr</span>,
<span class='texttt'>out_<span class='shy'></span>ptr_<span class='shy'></span>t</span>, <span class='texttt'>inout_<span class='shy'></span>ptr_<span class='shy'></span>t</span>, and various function
templates that operate on objects of these types (<a href='#smartptr' title='20.3&emsp;Smart pointers'>[smartptr]</a>)<a class='hidden_link' href='#memory.syn-1.sentence-2'>.</a></div>
  
  
  <div class='texpara'>
    <span class='codeblock'>
  <span class='keyword'>namespace</span> ranges <span class='curlybracket'>{</span>
    <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><a href='concept.destructible#concept:destructible' title='18.4.10&emsp;Concept destructible&emsp;[concept.destructible]'><span id='conceptref:destructible'><span class='tcode_in_codeblock'>destructible</span></span></a> T<span class='anglebracket'>&gt;</span>
      <span class='keyword'>constexpr</span> <span class='keyword'>void</span> destroy_at<span class='parenthesis'>(</span>T<span class='operator'>*</span> location<span class='parenthesis'>)</span> <span class='keyword'>noexcept</span>;                              <span class='comment'>// freestanding</span>

    <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><a href='special.mem.concepts#concept:nothrow-input-iterator' title='26.11.2&emsp;Special memory concepts&emsp;[special.mem.concepts]'><span id='conceptref:nothrow-input-iterator_'><span class='tcode_in_codeblock'><i >nothrow-input-iterator</i></span></span></a> I, <a href='special.mem.concepts#concept:nothrow-sentinel-for' title='26.11.2&emsp;Special memory concepts&emsp;[special.mem.concepts]'><span id='conceptref:nothrow-sentinel-for________'><span class='tcode_in_codeblock'><i >nothrow-sentinel-for</i></span></span></a><span class='anglebracket'>&lt;</span>I<span class='anglebracket'>&gt;</span> S<span class='anglebracket'>&gt;</span>
      <span class='keyword'>requires</span> <a href='concept.destructible#concept:destructible' title='18.4.10&emsp;Concept destructible&emsp;[concept.destructible]'><span id='conceptref:destructible_'><span class='tcode_in_codeblock'>destructible</span></span></a><span class='anglebracket'>&lt;</span>iter_value_t<span class='anglebracket'>&lt;</span>I<span class='anglebracket'>&gt;</span><span class='anglebracket'>&gt;</span>
        <span class='keyword'>constexpr</span> I destroy<span class='parenthesis'>(</span>I first, S last<span class='parenthesis'>)</span> <span class='keyword'>noexcept</span>;                              <span class='comment'>// freestanding</span>
    <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><a href='special.mem.concepts#concept:nothrow-input-range' title='26.11.2&emsp;Special memory concepts&emsp;[special.mem.concepts]'><span id='conceptref:nothrow-input-range_'><span class='tcode_in_codeblock'><i >nothrow-input-range</i></span></span></a> R<span class='anglebracket'>&gt;</span>
      <span class='keyword'>requires</span> <a href='concept.destructible#concept:destructible' title='18.4.10&emsp;Concept destructible&emsp;[concept.destructible]'><span id='conceptref:destructible__'><span class='tcode_in_codeblock'>destructible</span></span></a><span class='anglebracket'>&lt;</span>range_value_t<span class='anglebracket'>&lt;</span>R<span class='anglebracket'>&gt;</span><span class='anglebracket'>&gt;</span>
        <span class='keyword'>constexpr</span> borrowed_iterator_t<span class='anglebracket'>&lt;</span>R<span class='anglebracket'>&gt;</span> destroy<span class='parenthesis'>(</span>R<span class='operator'>&amp;</span><span class='operator'>&amp;</span> r<span class='parenthesis'>)</span> <span class='keyword'>noexcept</span>;                   <span class='comment'>// freestanding</span>

    <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><a href='special.mem.concepts#concept:nothrow-input-iterator' title='26.11.2&emsp;Special memory concepts&emsp;[special.mem.concepts]'><span id='conceptref:nothrow-input-iterator__'><span class='tcode_in_codeblock'><i >nothrow-input-iterator</i></span></span></a> I<span class='anglebracket'>&gt;</span>
      <span class='keyword'>requires</span> <a href='concept.destructible#concept:destructible' title='18.4.10&emsp;Concept destructible&emsp;[concept.destructible]'><span id='conceptref:destructible___'><span class='tcode_in_codeblock'>destructible</span></span></a><span class='anglebracket'>&lt;</span>iter_value_t<span class='anglebracket'>&lt;</span>I<span class='anglebracket'>&gt;</span><span class='anglebracket'>&gt;</span>
        <span class='keyword'>constexpr</span> I destroy_n<span class='parenthesis'>(</span>I first, iter_difference_t<span class='anglebracket'>&lt;</span>I<span class='anglebracket'>&gt;</span> n<span class='parenthesis'>)</span> <span class='keyword'>noexcept</span>;            <span class='comment'>// freestanding</span>
  <span class='curlybracket'>}</span>
  
<div class="added"><div class="added">  <span class='comment'>// <a href="#ptrtag">[ptrtag]</a>, pointer tagging</span>
  <span><span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> Ptr<span class='anglebracket'>&gt;</span>
    <span class='keyword'>struct</span> pointer_tag_traits;  <span class='comment'>// freestanding</span>
</span></div><div class="added">  <span><span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> Ptr, <span class='keyword'>class</span> TagT, 
    <span class='keyword'>unsigned</span> BitsRequested <span class='operator'>=</span> pointer_tag_traits&lt;Ptr&gt;::bits_available&lt;&gt;<span class='anglebracket'>&gt;</span>
      <span class='keyword'>class</span> pointer_tag_pair;  <span class='comment'>// freestanding</span></span></div><br/><div class="added">  template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_size&lt;pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt;
      : integral_constant&lt;size_t, 2&gt; { };
  template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_size&lt;const pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt;
      : integral_constant&lt;size_t, 2&gt; { };</div><br/><div class="added">  template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_element&lt;0, pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt; {
      using type = Ptr;
    };
    template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_element&lt;1, pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt; {
      using type = TagT;
    };</div><br/><div class="added">  template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_element&lt;0, const pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt; {
      using type = Ptr;
    };
  template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
    struct tuple_element&lt;1, const pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt; {
      using type = TagT;
    };</div>
</div>
  <span class='comment'>// <a href='#unique.ptr' title='20.3.1&emsp;Unique-ownership pointers'>[unique.<span class='shy'></span>ptr]</a>, class template <span class='tcode_in_codeblock'>unique_<span class='shy'></span>ptr</span></span>
  <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> T<span class='anglebracket'>&gt;</span> <span class='keyword'>struct</span> default_delete;                                          <span class='comment'>// freestanding</span>
  <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> T<span class='anglebracket'>&gt;</span> <span class='keyword'>struct</span> default_delete<span class='anglebracket'>&lt;</span>T<span class='squarebracket'>[</span><span class='squarebracket'>]</span><span class='anglebracket'>&gt;</span>;                                     <span class='comment'>// freestanding</span>
  <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> T, <span class='keyword'>class</span> D <span class='operator'>=</span> default_delete<span class='anglebracket'>&lt;</span>T<span class='anglebracket'>&gt;</span><span class='anglebracket'>&gt;</span> <span class='keyword'>class</span> unique_ptr;                  <span class='comment'>// freestanding</span>
  <span class='keyword'>template</span><span class='anglebracket'>&lt;</span><span class='keyword'>class</span> T, <span class='keyword'>class</span> D<span class='anglebracket'>&gt;</span> <span class='keyword'>class</span> unique_ptr<span class='anglebracket'>&lt;</span>T<span class='squarebracket'>[</span><span class='squarebracket'>]</span>, D<span class='anglebracket'>&gt;</span>;                              <span class='comment'>// freestanding</span>

</div></div>

</div>

<div class="section">
<div class="added">
<div id='ptrtag' class='section'><h3><a class='secnum' href='#ptrrag' style='min-width:65pt'>20.?</a> Pointer tagging <a class='abbr_ref' href='ptrtag'>[ptrtag]</a></h3></div></div>
<div class="added"><div id='ptrtag.traits' class='section'><h3 id="pointer-tag-trait"><a class='secnum' href='#ptrrag' style='min-width:65pt'>20.?.1</a> Class template <code>pointer_tag_traits</code> <a class='abbr_ref' href='ptrtag'>[ptrtag.traits]</a></h3></div>
</div>
<div class="added">
  <h3>20.?.1.1 General [ptrtag.traits.general]</h3>
  <div class='para' id='ptrtag-pair-1'><div class="sentence">The class template <code>pointer_tag_traits</code> provides the interface for accessing information about the free bits in pointer values that are usable in the <code>pointer_tag_pair</code> class template <a href="#ptrtag.pair">[ptrtag.pair]</a>.</div></div>
<pre><code>namespace std {  <span class="scroll-here"> </span>
<div class="added">  template &lt;typename T&gt; struct pointer_tag_traits; // see below</div>
<div class="added">  template &lt;typename Pointee&gt; 
  requires (std::is_object_v&lt;Pointee&gt;) 
    struct pointer_tag_traits&lt;Pointee *&gt; {
      template &lt;unsigned Alignment = alignof(Pointee)&gt;
        requires has_single_bit(Alignment)
          static constexpr bits_available = <em>see below</em>;
    };</div>
<div class="added">  template &lt;&gt; struct pointer_tag_traits&lt;void *&gt; {
    template &lt;unsigned Alignment = 1&gt;
      requires has_single_bit(Alignment)
        static constexpr bits_available = <em>see below</em>;
  };</div>
<div class="added">  template &lt;typename Pointee&gt; struct pointer_tag_traits&lt;const Pointee *&gt;: 
    pointer_tag_traits&lt;Pointee *&gt; { };</div>
};</code></pre>
</div>

<div class="added">
  <h3>20.?.1.3 <code>pointer_tag_traits</code> members [ptrtag.traits.members]</h3>
  <pre><code>template &lt;unsigned Alignment = alignof(Pointee)&gt;
  requires has_single_bit(Alignment)
    static constexpr bits_available = <em>see below</em>;
    
// <span id="support-for-void">pointer_tag_traits&lt;void *&gt; specialization</span>
template &lt;unsigned Alignment = 1&gt;
  requires has_single_bit(Alignment)
    static constexpr bits_available = <em>see below</em>;
  </code></pre>
  <div class="para">Implementation specific number of unused bits in the <code>Ptr *</code> and <code>void *</code> pointer representation.</div>
  <div class="note">Note: on reasonable platforms this value is <code>countr_zero(Alignment)</code>.</div>
</div>
  
<div class="section">
	<div class="added">
  <div id='ptrtag.pair' class='section'><h3><a class='secnum' href='#ptrrag' style='min-width:65pt'>20.?.2</a>
Class template <code>pointer_tag_pair</code> <a class='abbr_ref' href='ptrtag'>[ptrtag.pair]</a></h3></div>
  <div class="added">
  <h3>20.?.2.1 General [ptrtag.pair.general]</h3>
  <div class='para' id='ptrtag-general-1'><div class="sentence">The class template <code>pointer_tag_pair</code> provides a type to store an object pointer together with a tag value.</div></div>
</div></div>
<div class="added context">

<pre><code>namespace std {  <span class="scroll-here"> </span>
<div class="added">  template &lt;<span id="pointer-not-pointee">typename Ptr</span>, typename TagT,
    unsigned BitsRequested = pointer_tag_traits&lt;Ptr&gt;::bits_available&lt;&gt;&gt;
  class pointer_tag_pair {   // freestanding</div><div class="added">  public:
    using pointer_type        = Ptr;
    using tagged_pointer_type = conditional_t&lt;is_const_v&lt;pointer&gt;, const void *, void *&gt;;
    using tag_type            = TagT;
    static constexpr unsigned bits_requested = BitsRequested;</div><br><div class="added">    // Constructors and assignment
    constexpr pointer_tag_pair() noexcept;</div><br><div class="added">    template &lt;convertible_to&lt;pointer_type&gt; P&gt;
      requires((pointer_tag_traits&lt;P&gt;::bits_available&lt;&gt;) &gt;= bits_requested)
        constexpr pointer_tag_pair(P p, tag_type t);</div><br><div class="added">    // Special construction helpers
    template &lt;unsigned PromisedAlignment, convertible_to&lt;pointer_type&gt; P&gt;
      requires((pointer_tag_traits&lt;P&gt;::bits_available&lt;PromisedAlignment&gt;) &gt;= bits_requested)
        static constexpr pointer_tag_pair from_overaligned(P p, tag_type t);

    static pointer_tag_pair from_tagged(tagged_pointer_type p) noexcept; // note: not constexpr</div><br><div class="added">    // Accessors
    tagged_pointer_type tagged_pointer() const noexcept; // note: not constexpr
    constexpr pointer_type pointer() const noexcept;
    constexpr tag_type tag() const noexcept;</div><br><div class="added">    // Swap
    constexpr void swap(pointer_tag_pair&amp; o) noexcept;</div><br><div class="added">    // Comparisons
    friend constexpr <em>see-below</em> operator&lt;=&gt;(pointer_tag_pair lhs, pointer_tag_pair rhs) noexcept;
    friend bool operator==(pointer_tag_pair, pointer_tag_pair) = default;</div>
  };
}
</code></pre>
</div>
<div class="added">
<p>An object of class <code>pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;</code> represents a pair of pointer value <code>ptr</code> of type <code>PtrT</code> and tag value <code>tag</code> of type <code>TagT</code>.</p></div>
<div class="added">
<p>Each specialization <code>PT</code> of pointer_tag_pair is trivially copyable type that models <code>copyable</code> such that <code>sizeof(PT)</code> is equal <code>sizeof(Ptr)</code></p></div>
<div class="added"><p><strong>Mandates:</strong>
<ul>
<li><div class="added"><code>is_same_v&lt;remove_cvref_t&lt;Ptr&gt;, Ptr&gt; &amp;&amp; is_same_v&lt;remove_cvref_t&lt;TagT&gt;, TagT&gt;</code> is <code>true</code></div></li>
<li><div class="added"><code>is_pointer_v&lt;Ptr&gt; &amp;&amp; !is_function_v&lt;remove_pointer_t&lt;Ptr&gt;&gt;</code> is <code>true</code></div></li>
<li><div class="added"><code>is_unsigned_t&lt;UT&gt;</code> is <code>true</code>, where <code>UT</code> is <code>underlying_type_t&lt;TagT&gt;</code> if <code>TagT</code> is enumeration type, and <code>TagT</code> oherwise</div></li>
<li><div class="added"><code>sizeof(TagT) &lt;= sizeof(void*)</code>.</div></li>
</ul>
</p></div>


<div class="section">
<div class="added"><h3>20.?.2.2 Constructors and assignment [ptrtag.pair.cnstrassgnmt]</h3></div>

<div class="added">
<pre><code>constexpr pointer_tag_pair() noexcept;</code></pre>
<div class="para"><em>Effects</em>: Value-initializes <code>ptr</code> and <code>tag</code>.</div>
</div>

<div class="added">
<pre><code>template &lt;convertible_to&lt;pointer_type&gt; P&gt;
  requires((pointer_tag_traits&lt;P&gt;::bits_available&lt;&gt;) &gt;= bits_requested)
    constexpr pointer_tag_pair(P p, tag_type t);</code></pre>
<div class="added">
<div class="para"><em>Precondition</em>: <code>bit_width(t) &lt;= bits_requested</code> is <code>true</code>.</div>
</div>
<div class="added">
<div class="para"><em>Effects</em>: Initializes <code>ptr</code> with <code>p</code> and <code>tag</code> with <code>t</code>.</div>
</div>
<div class="added">
<div class="para"><em>Throws</em>: Nothing.</div>
</div>
</div>

</div>




<div class="section">
<div class="added">
<h3>20.?.2.3 Support for overaligned pointers [ptrtag.pair.overalign]</h3>
</div>
<div class="added">
<pre><code>template &lt;unsigned PromisedAlignment, convertible_to&lt;pointer_type&gt; P&gt;
  requires((pointer_tag_traits&lt;P&gt;::bits_available&lt;PromisedAlignment&gt;) &gt;= bits_requested)
    static constexpr pointer_tag_pair from_overaligned(P p, tag_type t);</code></pre>
<div class="added">
<div class="para"><em>Precondition</em>: 
  <ul>
  <li><code>is_sufficiently_aligned&lt;PromisedAlignment&gt;(p)</code> is <code>true</code>.</li>
  <li><code>bit_width(t) &lt;= bits_requested</code> is <code>true</code>.</li>
</ul>
</div>
</div>
<div class="added">
<div class="para"><em>Effects</em>: Initialized <code>ptr</code> with <code>p</code> and <code>tag</code> with <code>t</code>.</div>
</div>
<div class="added">
<div class="para"><em>Throws</em>: Nothing.</div>
</div>
</div>
</div>

<div class="section">
<div class="added">
<h3>20.?.2.4 Tagged pointer operations [ptrtag.pair.tagops]</h3>
</div>

<div class="added">
<pre><code>tagged_pointer_type tagged_pointer() const noexcept; // note: not constexpr</code></pre>
<div class="added">

<div class="para"><em>Returns</em>: An unspecified value <code>tp</code> of <code>tagged_pointer_type</code> type such that for any specialization <code>DP</code> of <code>pointer_tag_pair</code> and alignment value <code>A</code> for which: 
  <ul>
    <li><code>pointer_tag_traits&lt;void*&gt;::bits_available&lt;A&gt; &gt;= DP::bits_requested</code> is <code>true</code>,</li>
    <li><code>is_sufficiently_aligned&lt;A&gt;(ptr)</code> is <code>true</code>, and</li>
    <li><code>bit_width(tag) &lt;= DP::bits_requested</code> is <code>true</code>,</li>
  </ul> 
  <code>DP::from_tagged(tp)</code> produces object <code>dp</code> such that <code>reinterpret_cast&lt;Ptr&gt;(dp.pointer()) == ptr</code> is <code>true</code> and <code>static_cast&lt;TagT&gt;(dp.tag()) == tag</code> is <code>true</code>.
</div>

</div>
</div>

<div class="added">
<pre><code>static pointer_tag_pair from_tagged(tagged_pointer_type p) noexcept; // note: not constexpr</code></pre>

<div class="added">
<div class="para"><em>Returns</em>: An object <code>dp</code> of type <code>pointer_tag_type</code>, such that:
<ul>
<li>
  <p><code>reinterpret_cast&lt;Ptr&gt;(sp.pointer()) == dp.pointer()</code> is <code>true</code> and <code>static_cast&lt;TagT&gt;(sp.tag()) == dp.tag()</code> is <code>true</code>, if <code>p</code> is equal to <code>sp.tagged_pointer()</code> for some object <code>sp</code> of type that is specialization of <code>pointer_tag_type</code>, such that for some alignment value <code>A</code>:</p>
    <ul>
      <li><code>pointer_tag_traits&lt;void*&gt;::bits_available&lt;A&gt; &gt;= bits_requested</code> is <code>true</code>,</li>
      <li><code>is_sufficiently_aligned&lt;A&gt;(sp.pointer())</code> is <code>true</code>, and</li>
      <li><code>bit_width(sp.tag()) &lt;= bits_requested</code> is <code>true</code>,</li>
    </ul>
  </p>
</li>
<li>othewise, values of <code>dp.pointer()</code> and <code>dp.tag()</code> are unspecified.</li>
</ul>
</div>
</div>

</div>
</div>

<div class="section">
<div class="added">
	<h3>20.?.2.5 Accessors [ptrtag.pair.accessors]</h3>
</div>

<div class="added">
<pre><code>constexpr pointer_type pointer() const noexcept;</code></pre>
<div class="para"><em>Returns</em>: <code>ptr</code>.</div>
</div>

<div class="added">
<pre><code>constexpr tag_type tag() const noexcept;</code></pre>
<div class="para"><em>Returns</em>: <code>tag</code>.</div>
</div>



</div>

<div class="added">
<div class="section">
	<h3>20.?.2.6 Swap [ptrtag.pair.swap]</h3>
<pre><code>constexpr void swap(pointer_tag_pair&amp; o) noexcept;</code></pre>
<div class="para"><em>Effects</em>: Exchanges the values of <code>*this</code> and <code>o</code>.</div>
</div></div>

<div class="section">
<div class="added">
<h3>20.?.2.7 Comparison [ptrtag.pair.comparison]</h3>
</div>
<div class="added">
<pre><code>friend constexpr auto operator&lt;=&gt;(pointer_tag_pair lhs, pointer_tag_pair rhs) noexcept;</code></pre>
<div class="para"><em>Returns</em>: <code>tuple(lhs.pointer(), lhs.tag()) &lt;=&gt; tuple(rhs.pointer(), rhs.tag())</code>.</div>
</div>

<div class="added">
<pre><code>friend constexpr bool operator==(pointer_tag_pair lhs, pointer_tag_pair rhs) noexcept;</code></pre>
<div class="para"><em>Returns</em>: <code>lhs.pointer() == rhs.pointer() &amp;&amp; lhs.tag() == rhs.tag()</code>.</div>
</div>
</div>

<div class="section" id="tuple-like-interface">
  <div class="added">
    <h3>20.?.2.8 Tuple interface [ptrtag.pair.get]</h3>
 <div class="added">
  <pre><code>template&lt;class Ptr, class TagT, unsigned BitsRequested&gt;
  constexpr tuple_element_t&lt;I, pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt;&gt;
    get(pointer_tag_pair&lt;Ptr, TagT, BitsRequested&gt; p) noexcept;
  </code></pre>
  <div class="para"><em>Mandates</em>: <code>I &lt; 2</code></div>
  <div class="para"><em>Returns</em>:
    <ul class="itemize">
      <li><code>p.pointer()</code> if <code>I</code> is equal to zero,</li>
      <li><code>p.tag()</code> otherwise.</li>
    </ul>
  </div>
  </div>
</div>
</div>
</div>


</div>

</div>
</div>


</div>
	
<section data-related="feature-test-macro"><h3><a href="#feature-test-macro" id="feature-test-macro">Feature test macro</a></h3><div><h2><a href="http://eel.is/c++draft/version.syn">17.3.2 Header &lt;version&gt; synopsis [version.syn]</a></h2><div class="description"><span class="added"><code>#define __cpp_lib_pointer_tag_pair 2025??L // freestanding, also in &lt;memory&gt;</code></span></div></div>
</section></section></article>

<script>
	const all_changes = document.querySelectorAll(".wording .added, .wording .removed, .wording .change");
	let position = null;
	
	function set_hash(id) {
		const elem = document.getElementById(id);
		if (elem) {
			elem.id = `${id}-tmp`;
		}
		window.location.hash = id;
		if (elem) {
			elem.id = id;
		}
		return elem;
	}
	
	function disable_highlight_on_previous() {
		if (position != null) {
			//window.location.href.match(/([^#]++)#.++/);
			//window.location.
			set_hash("no-change-selected");
			// hljs is messing with me
			document.getElementById(all_changes[position].id).classList.remove("selected-current");
		}
	}
	
	function scroll_into_view_if_needed(el, scroll_there = true) {
		if (scroll_there) {
			if (!element_is_visible_in_viewport(el)) {
				el.scrollIntoView({behavior: "smooth", block: "center", inline: "center" });
			} else {
				console.log("doesn't need to scroll?!");
			}
		}
		
		return el;
	}
	
	function highlight_index(i = null, scroll_there = true) {
		if (position !== null && i === position) {
			console.log(`disabling overlay: ${i} === ${position}`);
			disable_highlight_on_previous();
			let overlay = document.querySelector("#overlay");
			overlay.remove();
			position = null;
			return;
		}
		
		if (i !== null) {
			disable_highlight_on_previous();
			position = i;
		}
		
		
		let overlay = document.querySelector("#overlay");
		if (!overlay) {
			let overlay = document.createElement("div");
			overlay.id = "overlay";
			document.querySelector("body").appendChild(overlay);
		}
		
		set_hash(`change-${position}`);
		
		
		const current = document.getElementById(all_changes[position].id);
		current.classList.add("selected-current");
		const scroll_anchor = current.querySelector(".scroll-here")
		
		if (scroll_anchor) {
			return scroll_into_view_if_needed(scroll_anchor, scroll_there);
		}
		
		return scroll_into_view_if_needed(current, scroll_there);
	}
	
	function element_is_visible_in_viewport(el) {
	  const { top, left, bottom, right } = el.getBoundingClientRect();
	  const { innerHeight, innerWidth } = window;
		const zoneHeight = innerHeight/5;
		const zoneWidth = innerWidth/5;
		
	  return top >= zoneHeight && bottom <= (innerHeight-zoneHeight);
	};
	
	all_changes.forEach((e, i) => {
		e.style.cursor = "pointer";
		e.id = `change-${i}-real`;
		e.onclick = (ev) => {
			current = highlight_index(i);
			
			ev.alreadyProcessed = true;
		}
	});
	
	document.body.onclick = (ev) => {
		if (position !== null && !ev.alreadyProcessed) {
			highlight_index(position, false);
		}
	};
	
	function next_or_previous_change(step) {
		disable_highlight_on_previous();

		const first = 0;
		const last =  all_changes.length - 1;
		
		if (position === null) {
			if (step < 0) {
				position = last;
			} else if (step > 0) {
				position = first;
			}
		} else {
			position += step;
		}
		
		if (position >= all_changes.length) {
			position = first;
		} else if (position < 0) {
			position = last;
		}
		highlight_index();
	}
	
	
	set_hash(window.location.hash);
	
	window.addEventListener("load", function () {
		const active_change = window.location.hash.match(/change-(?<id>[0-9]+)/);
		if (active_change) {
			const el = highlight_index(Number(active_change[1]), false);
			//console.log("scrolling there!");
			el.scrollIntoView({behavior: "instant", block: "center", inline: "center" });
		}
		window.setTimeout(() => {
			document.querySelector("html").style["scroll-behavior"] = "smooth";
		}, 500);
	});
	
	window.addEventListener("keydown", function (e) {
		if ((e.altKey) && e.code == "ArrowRight") {
			next_or_previous_change(1);
		} else if (position != null && e.code == "ArrowRight") {
			next_or_previous_change(1);
		} else if ((e.altKey) && e.code == "ArrowLeft") {
			next_or_previous_change(-1);
		} else if (position != null && e.code == "ArrowLeft") {
			next_or_previous_change(-1);
		} else if ((e.altKey) && e.code == "KeyF") {
			document.documentElement.requestFullscreen();
		}
	});
	
	const hide_button = document.getElementById("hide");
	hide_button.onclick = (e) => {
		if (hide_button.classList.contains("enabled")) {
			hide_button.classList.remove("enabled");
		} else {
			hide_button.classList.add("enabled");
		}
	};
	
	function navigate(e, elem) {
		//e.preventDefault();
		//return true;
		const target = elem.getAttribute("href");
		history.pushState(null, null, target);
		const target_element = document.getElementById(target.substr(1));
	}
	
	window.setTimeout(() => document.querySelector("article").classList.add("transitionable"), 500);
	
	document.querySelectorAll("a[href^=\"#\"]").forEach((elem) => { elem.onclick = (e) => navigate(e, elem); } );
	
	function send_email(link) {
		const [prefix, encoded] = link.getAttribute("href").split("#",2);
		window.location = "mailto:"+window.atob(encoded);
		return false;
	}
	
	document.querySelectorAll("a").forEach(link => {
		const relative = link.getAttribute("href");
		if (relative && !relative.startsWith("#") && !relative.startsWith("http://") && !relative.startsWith("https://")) {
			link.href= `https://eel.is/c++draft/${relative}`;
		}
		
	})
</script>

<!-- init-hljs.js -->
<script>
// trim must be first, before merge
hljs.addPlugin(trimNicely);
hljs.addPlugin(mergeHTMLPlugin);
hljs.highlightAll();

</script>
</body>
</html>
