<!DOCTYPE html>
<html>
<head>
  <meta charset=UTF-8 /><meta name=viewport content="width=device-width, initial-scale=1"/><link rel=preconnent href=https://fonts%2egoogleapis%2ecom />
  <link rel=preconnent href=https://fonts%2egstatic%2ecom crossorigin/>
  <link rel=stylesheet href="https://fonts%2egoogleapis%2ecom/css2?family=Fira+Code:wght@300%2e%2e700&family=Noto+Sans:ital,wght@0,100%2e%2e900;1,100%2e%2e900&family=Noto+Serif:ital,wght@0,100%2e%2e900;1,100%2e%2e900&display=swap"/>
  <style>
html {
    --sans-serif-family: "Noto Sans", sans-serif;
    --serif-family: "Noto Serif", serif;
    --monospace-family: "Fira Code", monospace;

    --light-background-color: white;
    --light-deep-background-color: #fafafa;
    --light-text-color: black;
    --light-border-color: #aaa;
    --light-table-border-color: #777;
    --light-del-color: #be1621;
    --light-del-background-color: #fbe6e8;
    --light-ins-color: #17752d;
    --light-ins-background-color: #e4faea;
    --light-para-color: rgb(10, 73, 136);
    --light-a-color: rgb(10, 73, 136);
    --light-a-visited-color: rgb(44, 10, 136);
    --light-a-hover-color: rgb(15, 93, 170);
    --light-mark-color: black;
    --light-mark-background-color: #ffff85;
    --light-abstract-border-color: #707070;
    --light-abstract-background-color: #f0f0f0;
    --light-abstract-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M660-160h40v-160h-40v160Zm20-200q8 0 14-6t6-14q0-8-6-14t-14-6q-8 0-14 6t-6 14q0 8 6 14t14 6ZM200-800v640-640 200-200Zm80 400h147q11-23 25.5-43t32.5-37H280v80Zm0 160h123q-3-20-3-40t3-40H280v80ZM200-80q-33 0-56.5-23.5T120-160v-640q0-33 23.5-56.5T200-880h320l240 240v92q-19-6-39-9t-41-3v-40H480v-200H200v640h227q11 23 25.5 43T485-80H200Zm480-400q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480Z"/></svg>');
    --light-blockquote-border-color: #707070;
    --light-blockquote-background-color: #f0f0f0;
    --light-blockquote-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="%23707070"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7.17 17c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94zm10 0c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94z"/></svg>');
    --light-bug-block-border-color: #9f7b5d;
    --light-bug-block-background-color: #f0e2d9;
    --light-bug-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%239f7b5d"><path d="M480-120q-64 0-114.5-33T283-240l-95 54-40-69 103-60q-3-11-5-22.5t-4-22.5H120v-80h122q2-12 4-23.5t5-22.5l-103-60 40-69 94 55q8-14 18.5-27.5T322-612q-2-7-2-14v-14q0-24 7-46t19-41l-66-66 56-57 70 68q17-9 35.5-13.5T480-800q20 0 39 5t36 14l69-69 56 57-66 66q12 19 18.5 41t6.5 46v13.5q0 6.5-2 13.5 11 11 21.5 25t18.5 28l95-54 40 69-104 59q3 11 5.5 22.5T718-440h122v80H718q-2 12-4 23.5t-5 22.5l103 60-40 69-95-55q-32 54-82.5 87T480-120Zm-76-546q17-7 36.5-10.5T480-680q20 0 38.5 3t35.5 10q-8-23-28-38t-46-15q-26 0-47 15.5T404-666Zm76 466q73 0 116.5-61T640-400q0-70-40.5-135T480-600q-78 0-119 64.5T320-400q0 78 43.5 139T480-200Zm-40-80v-240h80v240h-80Z"/></svg>');
    --light-decision-block-border-color: #ab6fa2;
    --light-decision-block-background-color: #f4e6f4;
    --light-decision-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6fa2"><path d="M160-120v-80h480v80H160Zm226-194L160-540l84-86 228 226-86 86Zm254-254L414-796l86-84 226 226-86 86Zm184 408L302-682l56-56 522 522-56 56Z"/></svg>');
    --light-del-block-border-color: #be1621;
    --light-del-block-background-color: #fbe6e8;
    --light-del-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23be1621"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>');
    --light-details-border-color: #707070;
    --light-details-background-color: #f0f0f0;
    --light-details-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --light-diff-block-border-color: #707070;
    --light-diff-block-background-color: #f0f0f0;
    --light-diff-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M500-520h80v-80h80v-80h-80v-80h-80v80h-80v80h80v80Zm-80 160h240v-80H420v80ZM320-200q-33 0-56.5-23.5T240-280v-560q0-33 23.5-56.5T320-920h280l240 240v400q0 33-23.5 56.5T760-200H320Zm0-80h440v-360L560-840H320v560ZM160-40q-33 0-56.5-23.5T80-120v-560h80v560h440v80H160Zm160-240v-560 560Z"/></svg>');
    --light-example-block-border-color: #6f8aab;
    --light-example-block-background-color: #e6e9f4;
    --light-example-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236f8aab"><path d="M300-80q-58 0-99-41t-41-99v-520q0-58 41-99t99-41h500v600q-25 0-42.5 17.5T740-220q0 25 17.5 42.5T800-160v80H300Zm-60-267q14-7 29-10t31-3h20v-440h-20q-25 0-42.5 17.5T240-740v393Zm160-13h320v-440H400v440Zm-160 13v-453 453Zm60 187h373q-6-14-9.5-28.5T660-220q0-16 3-31t10-29H300q-26 0-43 17.5T240-220q0 26 17 43t43 17Z"/></svg>');
    --light-important-block-border-color: #b05252;
    --light-important-block-background-color: #f4e6e6;
    --light-important-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6f6f"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>');
    --light-ins-block-border-color: #17752d;
    --light-ins-block-background-color: #e4faea;
    --light-ins-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%2317752d"><path d="M440-240h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>');
    --light-note-block-border-color: #6fab6f;
    --light-note-block-background-color: #e6f4e9;
    --light-note-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab6f"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --light-tip-block-border-color: #b0a029;
    --light-tip-block-background-color: #f4f4e6;
    --light-tip-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23b0a029"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-200v-80h320v80H320Zm10-120q-69-41-109.5-110T180-580q0-125 87.5-212.5T480-880q125 0 212.5 87.5T780-580q0 81-40.5 150T630-320H330Zm24-80h252q45-32 69.5-79T700-580q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 54 24.5 101t69.5 79Zm126 0Z"/></svg>');
    --light-todo-block-border-color: #6faba0;
    --light-todo-block-background-color: #e6f4f3;
    --light-todo-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236faba0"><path d="M680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80Zm67-105 28-28-75-75v-112h-40v128l87 87Zm-547 65q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v250q-18-13-38-22t-42-16v-212h-80v120H280v-120h-80v560h212q7 22 16 42t22 38H200Zm280-640q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>');
    --light-warning-block-border-color: #af8141;
    --light-warning-block-background-color: #f4eee6;
    --light-warning-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23af8141"><path d="M109-120q-11 0-20-5.5T75-140q-5-9-5.5-19.5T75-180l370-640q6-10 15.5-15t19.5-5q10 0 19.5 5t15.5 15l370 640q6 10 5.5 20.5T885-140q-5 9-14 14.5t-20 5.5H109Zm69-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm0-120q17 0 28.5-11.5T520-400v-120q0-17-11.5-28.5T480-560q-17 0-28.5 11.5T440-520v120q0 17 11.5 28.5T480-360Zm0-100Z"/></svg>');
    --light-theme-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="black"><path d="M480-360q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Zm0 80q-83 0-141.5-58.5T280-480q0-83 58.5-141.5T480-680q83 0 141.5 58.5T680-480q0 83-58.5 141.5T480-280ZM200-440H40v-80h160v80Zm720 0H760v-80h160v80ZM440-760v-160h80v160h-80Zm0 720v-160h80v160h-80ZM256-650l-101-97 57-59 96 100-52 56Zm492 496-97-101 53-55 101 97-57 59Zm-98-550 97-101 59 57-100 96-56-52ZM154-212l101-97 55 53-97 101-59-57Zm326-268Z"/></svg>');

    --dark-background-color: #202020;
    --dark-deep-background-color: #1a1a1a;
    --dark-text-color: #f0f0f0;
    --dark-border-color: #505050;
    --dark-table-border-color: #777;
    --dark-del-background-color: #67060c;
    --dark-del-color: #ffdcd7;
    --dark-ins-background-color: #033a16;
    --dark-ins-color: #aff5b4;
    --dark-para-color: #5bc0ff;
    --dark-a-color: #5bc0ff;
    --dark-a-visited-color: #c6a8ff;
    --dark-a-hover-color: #afd7ff;
    --dark-mark-color: #ededa8;
    --dark-mark-background-color: #525230;
    --dark-abstract-border-color: #999999;
    --dark-abstract-background-color: #2c2c2c;
    --dark-abstract-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23999999"><path d="M660-160h40v-160h-40v160Zm20-200q8 0 14-6t6-14q0-8-6-14t-14-6q-8 0-14 6t-6 14q0 8 6 14t14 6ZM200-800v640-640 200-200Zm80 400h147q11-23 25.5-43t32.5-37H280v80Zm0 160h123q-3-20-3-40t3-40H280v80ZM200-80q-33 0-56.5-23.5T120-160v-640q0-33 23.5-56.5T200-880h320l240 240v92q-19-6-39-9t-41-3v-40H480v-200H200v640h227q11 23 25.5 43T485-80H200Zm480-400q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480Z"/></svg>');
    --dark-blockquote-border-color: #707070;
    --dark-blockquote-background-color: #2c2c2c;
    --dark-blockquote-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="%23707070"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M7.17 17c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94zm10 0c.51 0 .98-.29 1.2-.74l1.42-2.84c.14-.28.21-.58.21-.89V8c0-.55-.45-1-1-1h-4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h2l-1.03 2.06c-.45.89.2 1.94 1.2 1.94z"/></svg>');
    --dark-bug-block-border-color: #ab866f;
    --dark-bug-block-background-color: #373028;
    --dark-bug-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab866f"><path d="M480-120q-64 0-114.5-33T283-240l-95 54-40-69 103-60q-3-11-5-22.5t-4-22.5H120v-80h122q2-12 4-23.5t5-22.5l-103-60 40-69 94 55q8-14 18.5-27.5T322-612q-2-7-2-14v-14q0-24 7-46t19-41l-66-66 56-57 70 68q17-9 35.5-13.5T480-800q20 0 39 5t36 14l69-69 56 57-66 66q12 19 18.5 41t6.5 46v13.5q0 6.5-2 13.5 11 11 21.5 25t18.5 28l95-54 40 69-104 59q3 11 5.5 22.5T718-440h122v80H718q-2 12-4 23.5t-5 22.5l103 60-40 69-95-55q-32 54-82.5 87T480-120Zm-76-546q17-7 36.5-10.5T480-680q20 0 38.5 3t35.5 10q-8-23-28-38t-46-15q-26 0-47 15.5T404-666Zm76 466q73 0 116.5-61T640-400q0-70-40.5-135T480-600q-78 0-119 64.5T320-400q0 78 43.5 139T480-200Zm-40-80v-240h80v240h-80Z"/></svg>');
    --dark-details-border-color: #707070;
    --dark-details-background-color: #2c2c2c;
    --dark-details-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --dark-decision-block-border-color: #ab6fa2;
    --dark-decision-block-background-color: #30232d;
    --dark-decision-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab6fa2"><path d="M160-120v-80h480v80H160Zm226-194L160-540l84-86 228 226-86 86Zm254-254L414-796l86-84 226 226-86 86Zm184 408L302-682l56-56 522 522-56 56Z"/></svg>');
    --dark-del-block-border-color: #be5e64;
    --dark-del-block-background-color: #302323;
    --dark-del-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23be5e64"><path d="M280-120q-33 0-56.5-23.5T200-200v-520h-40v-80h200v-40h240v40h200v80h-40v520q0 33-23.5 56.5T680-120H280Zm400-600H280v520h400v-520ZM360-280h80v-360h-80v360Zm160 0h80v-360h-80v360ZM280-720v520-520Z"/></svg>');
    --dark-diff-block-border-color: #707070;
    --dark-diff-block-background-color: #2c2c2c;
    --dark-diff-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23707070"><path d="M500-520h80v-80h80v-80h-80v-80h-80v80h-80v80h80v80Zm-80 160h240v-80H420v80ZM320-200q-33 0-56.5-23.5T240-280v-560q0-33 23.5-56.5T320-920h280l240 240v400q0 33-23.5 56.5T760-200H320Zm0-80h440v-360L560-840H320v560ZM160-40q-33 0-56.5-23.5T80-120v-560h80v560h440v80H160Zm160-240v-560 560Z"/></svg>');
    --dark-example-block-border-color: #6f81ab;
    --dark-example-block-background-color: #232630;
    --dark-example-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236f81ab"><path d="M300-80q-58 0-99-41t-41-99v-520q0-58 41-99t99-41h500v600q-25 0-42.5 17.5T740-220q0 25 17.5 42.5T800-160v80H300Zm-60-267q14-7 29-10t31-3h20v-440h-20q-25 0-42.5 17.5T240-740v393Zm160-13h320v-440H400v440Zm-160 13v-453 453Zm60 187h373q-6-14-9.5-28.5T660-220q0-16 3-31t10-29H300q-26 0-43 17.5T240-220q0 26 17 43t43 17Z"/></svg>');
    --dark-important-block-border-color: #b06262;
    --dark-important-block-background-color: #302323;
    --dark-important-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23b06262"><path d="M480-120q-33 0-56.5-23.5T400-200q0-33 23.5-56.5T480-280q33 0 56.5 23.5T560-200q0 33-23.5 56.5T480-120Zm-80-240v-480h160v480H400Z"/></svg>');
    --dark-ins-block-border-color: #5bab6d;
    --dark-ins-block-background-color: #233023;
    --dark-ins-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%235bab6d"><path d="M440-240h80v-120h120v-80H520v-120h-80v120H320v80h120v120ZM240-80q-33 0-56.5-23.5T160-160v-640q0-33 23.5-56.5T240-880h320l240 240v480q0 33-23.5 56.5T720-80H240Zm280-520v-200H240v640h480v-440H520ZM240-800v200-200 640-640Z"/></svg>');
    --dark-note-block-border-color: #6fab76;
    --dark-note-block-background-color: #233025;
    --dark-note-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab76"><path d="M440-280h80v-240h-80v240Zm40-320q17 0 28.5-11.5T520-640q0-17-11.5-28.5T480-680q-17 0-28.5 11.5T440-640q0 17 11.5 28.5T480-600Zm0 520q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>');
    --dark-tip-block-border-color: #a2ab6f;
    --dark-tip-block-background-color: #2f3023;
    --dark-tip-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23a2ab6f"><path d="M480-80q-33 0-56.5-23.5T400-160h160q0 33-23.5 56.5T480-80ZM320-200v-80h320v80H320Zm10-120q-69-41-109.5-110T180-580q0-125 87.5-212.5T480-880q125 0 212.5 87.5T780-580q0 81-40.5 150T630-320H330Zm24-80h252q45-32 69.5-79T700-580q0-92-64-156t-156-64q-92 0-156 64t-64 156q0 54 24.5 101t69.5 79Zm126 0Z"/></svg>');
    --dark-todo-block-border-color: #6fab98;
    --dark-todo-block-background-color: #23302e;
    --dark-todo-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%236fab98"><path d="M680-80q-83 0-141.5-58.5T480-280q0-83 58.5-141.5T680-480q83 0 141.5 58.5T880-280q0 83-58.5 141.5T680-80Zm67-105 28-28-75-75v-112h-40v128l87 87Zm-547 65q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h167q11-35 43-57.5t70-22.5q40 0 71.5 22.5T594-840h166q33 0 56.5 23.5T840-760v250q-18-13-38-22t-42-16v-212h-80v120H280v-120h-80v560h212q7 22 16 42t22 38H200Zm280-640q17 0 28.5-11.5T520-800q0-17-11.5-28.5T480-840q-17 0-28.5 11.5T440-800q0 17 11.5 28.5T480-760Z"/></svg>');
    --dark-warning-block-border-color: #ab9c6f;
    --dark-warning-block-background-color: #302b23;
    --dark-warning-block-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23ab9c6f"><path d="M109-120q-11 0-20-5.5T75-140q-5-9-5.5-19.5T75-180l370-640q6-10 15.5-15t19.5-5q10 0 19.5 5t15.5 15l370 640q6 10 5.5 20.5T885-140q-5 9-14 14.5t-20 5.5H109Zm69-80h604L480-720 178-200Zm302-40q17 0 28.5-11.5T520-280q0-17-11.5-28.5T480-320q-17 0-28.5 11.5T440-280q0 17 11.5 28.5T480-240Zm0-120q17 0 28.5-11.5T520-400v-120q0-17-11.5-28.5T480-560q-17 0-28.5 11.5T440-520v120q0 17 11.5 28.5T480-360Zm0-100Z"/></svg>');
    --dark-theme-icon: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="%23f0f0f0"><path d="M480-120q-150 0-255-105T120-480q0-150 105-255t255-105q14 0 27.5 1t26.5 3q-41 29-65.5 75.5T444-660q0 90 63 153t153 63q55 0 101-24.5t75-65.5q2 13 3 26.5t1 27.5q0 150-105 255T480-120Zm0-80q88 0 158-48.5T740-375q-20 5-40 8t-40 3q-123 0-209.5-86.5T364-660q0-20 3-40t8-40q-78 32-126.5 102T200-480q0 116 82 198t198 82Zm-10-270Z"/></svg>');

    --indent: 2.5em;
    --border-radius: 0.25em;
}

/* BEGIN LIGHT AND DARK THEME */

@media (prefers-color-scheme: light) {
    html {
        --background-color: var(--light-background-color);
        --deep-background-color: var(--light-deep-background-color);
        --text-color: var(--light-text-color);
        --border-color: var(--light-border-color);
        --table-border-color: var(--light-table-border-color);
        --del-color: var(--light-del-color);
        --del-background-color: var(--light-del-background-color);
        --ins-color: var(--light-ins-color);
        --ins-background-color: var(--light-ins-background-color);
        --para-color: var(--light-para-color);
        --a-color: var(--light-a-color);
        --a-visited-color: var(--light-a-visited-color);
        --a-hover-color: var(--light-a-hover-color);
        --mark-color: var(--light-mark-color);
        --mark-background-color: var(--light-mark-background-color);
        --abstract-border-color: var(--light-abstract-border-color);
        --abstract-background-color: var(--light-abstract-background-color);
        --abstract-image: var(--light-abstract-image);
        --blockquote-border-color: var(--light-blockquote-border-color);
        --blockquote-background-color: var(--light-blockquote-background-color);
        --blockquote-image: var(--light-blockquote-image);
        --bug-block-border-color: var(--light-bug-block-border-color);
        --bug-block-background-color: var(--light-bug-block-background-color);
        --bug-block-image: var(--light-bug-block-image);
        --decision-block-border-color: var(--light-decision-block-border-color);
        --decision-block-background-color: var(--light-decision-block-background-color);
        --decision-block-image: var(--light-decision-block-image);
        --del-block-border-color: var(--light-del-block-border-color);
        --del-block-background-color: var(--light-del-block-background-color);
        --del-block-image: var(--light-del-block-image);
        --details-border-color: var(--light-details-border-color);
        --details-background-color: var(--light-details-background-color);
        --details-image: var(--light-details-image);
        --diff-block-border-color: var(--light-diff-block-border-color);
        --diff-block-background-color: var(--light-diff-block-background-color);
        --diff-block-image: var(--light-diff-block-image);
        --example-block-border-color: var(--light-example-block-border-color);
        --example-block-background-color: var(--light-example-block-background-color);
        --example-block-image: var(--light-example-block-image);
        --important-block-border-color: var(--light-important-block-border-color);
        --important-block-background-color: var(--light-important-block-background-color);
        --important-block-image: var(--light-important-block-image);
        --ins-block-border-color: var(--light-ins-block-border-color);
        --ins-block-background-color: var(--light-ins-block-background-color);
        --ins-block-image: var(--light-ins-block-image);
        --note-block-border-color: var(--light-note-block-border-color);
        --note-block-background-color: var(--light-note-block-background-color);
        --note-block-image: var(--light-note-block-image);
        --tip-block-border-color: var(--light-tip-block-border-color);
        --tip-block-background-color: var(--light-tip-block-background-color);
        --tip-block-image: var(--light-tip-block-image);
        --todo-block-border-color: var(--light-todo-block-border-color);
        --todo-block-background-color: var(--light-todo-block-background-color);
        --todo-block-image: var(--light-todo-block-image);
        --warning-block-border-color: var(--light-warning-block-border-color);
        --warning-block-background-color: var(--light-warning-block-background-color);
        --warning-block-image: var(--light-warning-block-image);
        --theme-icon: var(--light-theme-icon);
    }
}

@media (prefers-color-scheme: dark) {
    html {
        --background-color: var(--dark-background-color);
        --deep-background-color: var(--dark-deep-background-color);
        --text-color: var(--dark-text-color);
        --border-color: var(--dark-border-color);
        --table-border-color: var(--dark-table-border-color);
        --del-color: var(--dark-del-color);
        --del-background-color: var(--dark-del-background-color);
        --ins-color: var(--dark-ins-color);
        --ins-background-color: var(--dark-ins-background-color);
        --para-color: var(--dark-para-color);
        --a-color: var(--dark-a-color);
        --a-visited-color: var(--dark-a-visited-color);
        --a-hover-color: var(--dark-a-hover-color);
        --mark-color: var(--dark-mark-color);
        --mark-background-color: var(--dark-mark-background-color);
        --abstract-border-color: var(--dark-abstract-border-color);
        --abstract-background-color: var(--dark-abstract-background-color);
        --abstract-image: var(--dark-abstract-image);
        --blockquote-border-color: var(--dark-blockquote-border-color);
        --blockquote-background-color: var(--dark-blockquote-background-color);
        --blockquote-image: var(--dark-blockquote-image);
        --bug-block-border-color: var(--dark-bug-block-border-color);
        --bug-block-background-color: var(--dark-bug-block-background-color);
        --bug-block-image: var(--dark-bug-block-image);
        --decision-block-border-color: var(--dark-decision-block-border-color);
        --decision-block-background-color: var(--dark-decision-block-background-color);
        --decision-block-image: var(--dark-decision-block-image);
        --del-block-border-color: var(--dark-del-block-border-color);
        --del-block-background-color: var(--dark-del-block-background-color);
        --del-block-image: var(--dark-del-block-image);
        --details-border-color: var(--dark-details-border-color);
        --details-background-color: var(--dark-details-background-color);
        --details-image: var(--dark-details-image);
        --diff-block-border-color: var(--dark-diff-block-border-color);
        --diff-block-background-color: var(--dark-diff-block-background-color);
        --diff-block-image: var(--dark-diff-block-image);
        --example-block-border-color: var(--dark-example-block-border-color);
        --example-block-background-color: var(--dark-example-block-background-color);
        --example-block-image: var(--dark-example-block-image);
        --important-block-border-color: var(--dark-important-block-border-color);
        --important-block-background-color: var(--dark-important-block-background-color);
        --important-block-image: var(--dark-important-block-image);
        --ins-block-border-color: var(--dark-ins-block-border-color);
        --ins-block-background-color: var(--dark-ins-block-background-color);
        --ins-block-image: var(--dark-ins-block-image);
        --note-block-border-color: var(--dark-note-block-border-color);
        --note-block-background-color: var(--dark-note-block-background-color);
        --note-block-image: var(--dark-note-block-image);
        --tip-block-border-color: var(--dark-tip-block-border-color);
        --tip-block-background-color: var(--dark-tip-block-background-color);
        --tip-block-image: var(--dark-tip-block-image);
        --todo-block-border-color: var(--dark-todo-block-border-color);
        --todo-block-background-color: var(--dark-todo-block-background-color);
        --todo-block-image: var(--dark-todo-block-image);
        --warning-block-border-color: var(--dark-warning-block-border-color);
        --warning-block-background-color: var(--dark-warning-block-background-color);
        --warning-block-image: var(--dark-warning-block-image);
        --theme-icon: var(--dark-theme-icon);
    }
}

html.light {
    --background-color: var(--light-background-color);
    --deep-background-color: var(--light-deep-background-color);
    --text-color: var(--light-text-color);
    --border-color: var(--light-border-color);
    --table-border-color: var(--light-table-border-color);
    --del-color: var(--light-del-color);
    --del-background-color: var(--light-del-background-color);
    --ins-color: var(--light-ins-color);
    --ins-background-color: var(--light-ins-background-color);
    --para-color: var(--light-para-color);
    --a-color: var(--light-a-color);
    --a-visited-color: var(--light-a-visited-color);
    --a-hover-color: var(--light-a-hover-color);
    --mark-color: var(--light-mark-color);
    --mark-background-color: var(--light-mark-background-color);
    --abstract-border-color: var(--light-abstract-border-color);
    --abstract-background-color: var(--light-abstract-background-color);
    --abstract-image: var(--light-abstract-image);
    --blockquote-border-color: var(--light-blockquote-border-color);
    --blockquote-background-color: var(--light-blockquote-background-color);
    --blockquote-image: var(--light-blockquote-image);
    --bug-block-border-color: var(--light-bug-block-border-color);
    --bug-block-background-color: var(--light-bug-block-background-color);
    --bug-block-image: var(--light-bug-block-image);
    --decision-block-border-color: var(--light-decision-block-border-color);
    --decision-block-background-color: var(--light-decision-block-background-color);
    --decision-block-image: var(--light-decision-block-image);
    --del-block-border-color: var(--light-del-block-border-color);
    --del-block-background-color: var(--light-del-block-background-color);
    --del-block-image: var(--light-del-block-image);
    --details-border-color: var(--light-details-border-color);
    --details-background-color: var(--light-details-background-color);
    --details-image: var(--light-details-image);
    --diff-block-border-color: var(--light-diff-block-border-color);
    --diff-block-background-color: var(--light-diff-block-background-color);
    --diff-block-image: var(--light-diff-block-image);
    --example-block-border-color: var(--light-example-block-border-color);
    --example-block-background-color: var(--light-example-block-background-color);
    --example-block-image: var(--light-example-block-image);
    --important-block-border-color: var(--light-important-block-border-color);
    --important-block-background-color: var(--light-important-block-background-color);
    --important-block-image: var(--light-important-block-image);
    --ins-block-border-color: var(--light-ins-block-border-color);
    --ins-block-background-color: var(--light-ins-block-background-color);
    --ins-block-image: var(--light-ins-block-image);
    --note-block-border-color: var(--light-note-block-border-color);
    --note-block-background-color: var(--light-note-block-background-color);
    --note-block-image: var(--light-note-block-image);
    --tip-block-border-color: var(--light-tip-block-border-color);
    --tip-block-background-color: var(--light-tip-block-background-color);
    --tip-block-image: var(--light-tip-block-image);
    --todo-block-border-color: var(--light-todo-block-border-color);
    --todo-block-background-color: var(--light-todo-block-background-color);
    --todo-block-image: var(--light-todo-block-image);
    --warning-block-border-color: var(--light-warning-block-border-color);
    --warning-block-background-color: var(--light-warning-block-background-color);
    --warning-block-image: var(--light-warning-block-image);
    --theme-icon: var(--light-theme-icon);
}

html.dark {
    --background-color: var(--dark-background-color);
    --deep-background-color: var(--dark-deep-background-color);
    --text-color: var(--dark-text-color);
    --border-color: var(--dark-border-color);
    --table-border-color: var(--dark-table-border-color);
    --del-color: var(--dark-del-color);
    --del-background-color: var(--dark-del-background-color);
    --ins-color: var(--dark-ins-color);
    --ins-background-color: var(--dark-ins-background-color);
    --para-color: var(--dark-para-color);
    --a-color: var(--dark-a-color);
    --a-visited-color: var(--dark-a-visited-color);
    --a-hover-color: var(--dark-a-hover-color);
    --mark-color: var(--dark-mark-color);
    --mark-background-color: var(--dark-mark-background-color);
    --abstract-border-color: var(--dark-abstract-border-color);
    --abstract-background-color: var(--dark-abstract-background-color);
    --abstract-image: var(--dark-abstract-image);
    --blockquote-border-color: var(--dark-blockquote-border-color);
    --blockquote-background-color: var(--dark-blockquote-background-color);
    --blockquote-image: var(--dark-blockquote-image);
    --bug-block-border-color: var(--dark-bug-block-border-color);
    --bug-block-background-color: var(--dark-bug-block-background-color);
    --bug-block-image: var(--dark-bug-block-image);
    --decision-block-border-color: var(--dark-decision-block-border-color);
    --decision-block-background-color: var(--dark-decision-block-background-color);
    --decision-block-image: var(--dark-decision-block-image);
    --del-block-border-color: var(--dark-del-block-border-color);
    --del-block-background-color: var(--dark-del-block-background-color);
    --del-block-image: var(--dark-del-block-image);
    --details-border-color: var(--dark-details-border-color);
    --details-background-color: var(--dark-details-background-color);
    --details-image: var(--dark-details-image);
    --diff-block-border-color: var(--dark-diff-block-border-color);
    --diff-block-background-color: var(--dark-diff-block-background-color);
    --diff-block-image: var(--dark-diff-block-image);
    --example-block-border-color: var(--dark-example-block-border-color);
    --example-block-background-color: var(--dark-example-block-background-color);
    --example-block-image: var(--dark-example-block-image);
    --important-block-border-color: var(--dark-important-block-border-color);
    --important-block-background-color: var(--dark-important-block-background-color);
    --important-block-image: var(--dark-important-block-image);
    --ins-block-border-color: var(--dark-ins-block-border-color);
    --ins-block-background-color: var(--dark-ins-block-background-color);
    --ins-block-image: var(--dark-ins-block-image);
    --note-block-border-color: var(--dark-note-block-border-color);
    --note-block-background-color: var(--dark-note-block-background-color);
    --note-block-image: var(--dark-note-block-image);
    --tip-block-border-color: var(--dark-tip-block-border-color);
    --tip-block-background-color: var(--dark-tip-block-background-color);
    --tip-block-image: var(--dark-tip-block-image);
    --todo-block-border-color: var(--dark-todo-block-border-color);
    --todo-block-background-color: var(--dark-todo-block-background-color);
    --todo-block-image: var(--dark-todo-block-image);
    --warning-block-border-color: var(--dark-warning-block-border-color);
    --warning-block-background-color: var(--dark-warning-block-background-color);
    --warning-block-image: var(--dark-warning-block-image);
    --theme-icon: var(--dark-theme-icon);
}

/* END LIGHT AND DARK THEME */

html {
    margin: 0;
    width: 100%;
    font-family: var(--serif-family);
    font-size: 11pt;

    border-left: var(--border-thickness) solid var(--border-color);
    color: var(--text-color);
    background-color: var(--background-color);
}

body {
    --vertical-margin: 2rem;
    --margin-left: 3rem;
    --margin-right: 2rem;

    margin: var(--vertical-margin) var(--margin-right) var(--vertical-margin) var(--margin-left);
    width: calc(100% - var(--margin-left) - var(--margin-right));
    box-sizing: border-box;
}

main {
    max-width: 60rem;
    margin-left: auto;
    margin-right: auto;
}

p {
    text-align: justify;
}

abstract-block,
blockquote,
bug-block,
code-block,
decision-block,
del-block,
details,
dl,
diff-block,
example-block,
hr,
ol,
important-block,
ins-block,
math[display=block],
note-block,
p,
pre,
tip-block,
todo-block,
ul,
warning-block,
.indent {
    display: block;
    margin-top: 1em;
    margin-bottom: 1em;
}

a {
    color: var(--a-color);
    text-decoration: unset;
}

a:visited {
    color: var(--a-visited-color);
}

a:hover,
a:focus {
    color: var(--a-hover-color);
}

a:hover {
    text-decoration: underline;
}

ol,
ul {
    padding-left: var(--indent);
}

li {
    margin: 0.5em 0;
}

dt {
    margin-top: 0.25em;
    font-style: italic;
    font-weight: bold;
}

dd {
    margin-bottom: 0.25em;
    margin-left: var(--indent);
}

abstract-block,
blockquote,
bug-block,
del-block,
details,
decision-block,
diff-block,
example-block,
important-block,
ins-block,
note-block,
tip-block,
todo-block,
warning-block {
    --border-thickness: 0.25em;
    --padding: 0.5em;

    position: relative;
    width: calc(100% - var(--indent));
    box-sizing: border-box;
    padding: var(--padding);
    margin-left: var(--indent);

    border-top-right-radius: var(--border-radius);
    border-bottom-right-radius: var(--border-radius);
}

abstract-block>:first-child,
blockquote>:first-child,
bug-block>:first-child,
del-block>:first-child,
details>:first-child,
decision-block>:first-child,
diff-block>:first-child,
example-block>:first-child,
important-block>:first-child,
ins-block>:first-child,
note-block>:first-child,
tip-block>:first-child,
todo-block>:first-child,
warning-block>:first-child {
    margin-top: 0;
}

abstract-block>:last-child,
blockquote>:last-child,
bug-block>:last-child,
del-block>:last-child,
details>:last-child,
decision-block>:last-child,
diff-block>:last-child,
example-block>:last-child,
important-block>:last-child,
ins-block>:last-child,
note-block>:last-child,
todo-block>:last-child,
tip-block>:last-child,
warning-block>:last-child {
    margin-bottom: 0;
}

abstract-block::before,
blockquote::before,
bug-block::before,
del-block::before,
details::before,
decision-block::before,
diff-block::before,
example-block::before,
important-block::before,
ins-block::before,
note-block::before,
todo-block::before,
tip-block::before,
warning-block::before {
    position: absolute;
    left: -2.5em;
    top: 0.25em;
    width: 2em;
    height: 2em;

    content: "";
    display: inline-block;
    background-size: contain;
    background-repeat: no-repeat;

}

code,
code-block,
pre,
samp,
tt,
tt-,
.mono {
    font-family: var(--monospace-family);
    font-style: normal;
    font-variant-ligatures: none;
}

code-block:not(.borderless),
pre {
    padding: 0.5em;
    border-radius: var(--border-radius);
    box-sizing: border-box;

    background-color: var(--deep-background-color);
    border: 1px solid var(--border-color);
}

code-block,
pre {
    font-size: 95%;
    width: 100%;
}

code-block,
pre {
    white-space: pre;
    overflow-x: auto;
}

/* INSERTIONS AND DELETIONS */

ins,
ins-lines {
    text-decoration: underline;
    font-weight: 600;
    color: var(--ins-color);
    background-color: var(--ins-background-color);
}

code-block ins,
code-block ins-lines {
    text-decoration: inherit;
}

del {
    text-decoration: line-through;
}

del,
del-lines {
    color: var(--del-color);
    background-color: var(--del-background-color);
}

ins-lines,
del-lines {
    display: inline-block;
    width: 100%;
}

ins h-,
ins-lines h-,
del h-,
del-lines h- {
    color: inherit !important;
    background-color: inherit !important;
}

kbd {
    font-family: var(--sans-serif-family);

    display: inline-block;
    padding: 0 0.25em 0.15em 0.25em;
    border-radius: 0.25em;
    white-space: nowrap;

    background-color: var(--deep-background-color);
    border: 1px solid var(--border-color);
    box-shadow: inset 0 -0.1em 0 var(--border-color);
}

mark {
    color: var(--mark-color);
    background-color: var(--mark-background-color);
}

math:not([display=block]) {
    font-size: 120%;
}

math[display=block] {
    width: fit-content;
    margin-left: var(--indent);

    font-size: 110%;
}

g-term,
f-sans,
f-serif,
wg21-block {
    display: inline;
}

f-sans,
.sans {
    font-family: var(--sans-serif-family);
}

f-serif,
.serif {
    font-family: var(--serif-family);
}

.grammar dd,
g-term {
    font-family: var(--sans-serif-family);
    font-style: oblique;
}

.grammar {
    margin-left: var(--indent);
}

.grammar dt {
    font-weight: normal;
    font-style: normal;
}

.oblique {
    font-style: oblique;
}

.word {
    white-space: nowrap;
}

.wg21-head {
    margin-bottom: 4em;
}

.wg21-head dl {
    font-family: var(--sans-serif-family);
}

.wg21-head dt {
    font-style: normal;
}

/* HEADINGS */

h1,
h2,
h3,
h4,
h5,
h6 {
    position: relative;
    margin: 1rem 0;
}

h1 {
    margin: 2rem 0 1.5rem 0;
    font-size: 250%;
}

h2 {
    margin: 2.5rem 0 1.5rem 0;
    font-size: 166%;
}

h3 {
    margin: 2rem 0 1rem 0;
    font-size: 133%;
}

h4 {
    margin: 1.5rem 0 0.5rem 0;
    font-size: 100%;
}

h5 {
    margin: 1rem 0 0.5rem 0;
    font-size: 100%;
    font-weight: normal;
}

h6 {
    margin: 1rem 0 0.5rem 0;
    font-size: 90%;
    font-weight: normal;
}

table {
    --border: 1px solid var(--table-border-color);

    margin-top: 1em;
    margin-bottom: 1em;
    border-collapse: collapse;
}

table,
tbody,
thead,
th {
    border: var(--border);
}

td {
    border-left: var(--border);
    border-right: var(--border);
}

td,
th {
    padding: 0.1em 0.5em;
}

.para {
    cursor: pointer;
    font-weight: normal;
    font-family: var(--monospace-family);
    text-decoration: none;
    opacity: 0.25;

    position: absolute;
    top: 0.05em;
    left: calc(-1rem - 0.5ch);
}

.para,
.para::before {
    color: var(--para-color);
}

.para:hover,
.para:focus,
:target .para {
    opacity: 1;
}

.para::before {
    content: "§";
}

/* TABLE OF CONTENTS */

.toc {
    --h-indent: 0.75em;

    display: grid;
    grid-template-columns: min-content auto;
}

.toc-num {
    display: inline-block;
    align-self: end;
    padding-right: 3em;

    letter-spacing: 0em;
}

.toc h1,
.toc h2,
.toc h3,
.toc h4,
.toc h5,
.toc h6 {
    display: inline-block;

    font-weight: 500;
    font-size: 12pt;

    margin-top: 0;
    margin-bottom: 0;
}

.toc a,
.toc-num {
    border-bottom: 1px solid rgba(0, 0, 0, 0);
    color: var(--text-color);
}

.toc h1,
.toc-num[data-level="1"] {
    font-size: 125%;
    font-weight: 900;
}

.toc h2,
.toc-num[data-level="2"] {
    font-weight: 700;
}

.toc h3,
.toc-num[data-level="3"] {
    font-weight: 500;
}

.toc h4,
.toc-num[data-level="4"] {
    font-size: 95%;
    font-weight: 400;
}

.toc h5,
.toc-num[data-level="5"] {
    font-size: 90%;
    font-weight: 300;
}

.toc h6,
.toc-num[data-level="6"] {
    font-size: 90%;
    font-weight: 100;
}

.toc a:hover {
    display: inline-block;
    width: 100%;

    color: var(--a-hover-color);
    border-bottom: 1px dashed var(--a-hover-color);
}

.toc h1:not(:nth-child(2)>h1) {
    margin-top: 1.5em;
}

.toc h2:not(:nth-child(2)>h2) {
    margin-top: 0.75em;
}

/** BIBLIOGRAPHY */

.bib {
    display: block;
    margin: 1em 0;
}

.bib-item {
    display: inline-block;
    width: 100%;
    margin: 0.25em 0;
}

.bib-item>* {
    padding: 0 0.125em;
}

.bib-author {
    font-style: italic;
}

.bib-title {
    font-weight: 500;
}

.bib-date {
    font-family: var(--monospace-family);
}

.bib-date::before {
    font-family: var(--serif-family);
    content: "(";
}

.bib-date::after {
    font-family: var(--serif-family);
    content: ")";
}

.bib-link {
    display: block;
    margin-left: var(--indent);

    font-family: var(--sans-serif-family);
    font-style: normal;
}

/* SPECIAL BLOCKS */

intro- {
    display: inline-block;

    font-weight: 600;
    text-transform: uppercase;
    font-family: var(--sans-serif-family);
}

abstract-block {
    background-color: var(--abstract-background-color);
    border-left: var(--border-thickness) solid var(--abstract-border-color);
}

abstract-block::before {
    background-image: var(--abstract-image);
}

abstract-block intro-::before {
    content: "Abstract:";
    color: var(--abstract-border-color);
}

blockquote {
    background-color: var(--blockquote-background-color);
    border-left: var(--border-thickness) solid var(--blockquote-border-color);
}

blockquote::before {
    background-image: var(--blockquote-image);
    top: -0.25em;
}

blockquote intro-::before {
    content: "Quote:";
    color: var(--blockquote-border-color);
}

bug-block {
    background-color: var(--bug-block-background-color);
    border-left: var(--border-thickness) solid var(--bug-block-border-color);
}

bug-block::before {
    background-image: var(--bug-block-image);
}

bug-block intro-::before {
    content: "Bug:";
    color: var(--bug-block-border-color);
}

del-block {
    background-color: var(--del-block-background-color);
    border-left: var(--border-thickness) solid var(--del-block-border-color);
    color: var(--del-color);
}

del-block::before {
    background-image: var(--del-block-image);
}

del-block intro-::before {
    content: "Deleted:";
    color: var(--del-block-border-color);
}

del-block code,
del-block code-block {
    color: var(--text-color);
}

details {
    background-color: var(--details-background-color);
    border-left: var(--border-thickness) solid var(--details-border-color);
}

details::before {
    background-image: var(--details-image);
}

summary {
    font-family: var(--sans-serif-family);
    color: var(--details-border-color);
    user-select: none;
    cursor: pointer;
}

details[open]>summary {
    margin-bottom: 0.5em;
}

decision-block {
    background-color: var(--decision-block-background-color);
    border-left: var(--border-thickness) solid var(--decision-block-border-color);
}

decision-block::before {
    background-image: var(--decision-block-image);
}

decision-block intro-::before {
    content: "Decision:";
    color: var(--decision-block-border-color);
}

diff-block {
    background-color: var(--diff-block-background-color);
    border-left: var(--border-thickness) solid var(--diff-block-border-color);
}

diff-block::before {
    background-image: var(--diff-block-image);
}

diff-block intro-::before {
    content: "Difference:";
    color: var(--diff-block-border-color);
}

example-block {
    background-color: var(--example-block-background-color);
    border-left: var(--border-thickness) solid var(--example-block-border-color);
}

example-block::before {
    background-image: var(--example-block-image);
}

example-block intro-::before {
    content: "Example:";
    color: var(--example-block-border-color);
}

important-block {
    background-color: var(--important-block-background-color);
    border-left: var(--border-thickness) solid var(--important-block-border-color);
}

important-block::before {
    background-image: var(--important-block-image);
}

important-block intro-::before {
    content: "Important:";
    color: var(--important-block-border-color);
}

ins-block {
    background-color: var(--ins-block-background-color);
    border-left: var(--border-thickness) solid var(--ins-block-border-color);
    color: var(--ins-color);
}

ins-block code,
ins-block code-block {
    color: var(--text-color);
}

ins-block::before {
    background-image: var(--ins-block-image);
}

ins-block intro-::before {
    content: "Inserted:";
    color: var(--ins-block-border-color);
}

note-block {
    background-color: var(--note-block-background-color);
    border-left: var(--border-thickness) solid var(--note-block-border-color);
}

note-block::before {
    background-image: var(--note-block-image);
}

note-block intro-::before {
    content: "Note:";
    color: var(--note-block-border-color);
}

tip-block {
    background-color: var(--tip-block-background-color);
    border-left: var(--border-thickness) solid var(--tip-block-border-color);
}

tip-block::before {
    background-image: var(--tip-block-image);
}

tip-block intro-::before {
    content: "Tip:";
    color: var(--tip-block-border-color);
}

todo-block {
    background-color: var(--todo-block-background-color);
    border-left: var(--border-thickness) solid var(--todo-block-border-color);
}

todo-block::before {
    background-image: var(--todo-block-image);
}

todo-block intro-::before {
    content: "Todo:";
    color: var(--todo-block-border-color);
}

warning-block {
    background-color: var(--warning-block-background-color);
    border-left: var(--border-thickness) solid var(--warning-block-border-color);
}

warning-block::before {
    background-image: var(--warning-block-image);
}

warning-block intro-::before {
    content: "Warning:";
    color: var(--warning-block-border-color);
}

.indent {
    margin-left: var(--indent);
}

/* SETTINGS MENU */

#settings:not(.js) {
    display: none;
}

#settings {
    z-index: 999;
    position: fixed;
    display: inline-block;
    top: 1em;
    right: 1em;
}

#theme-icon {
    display: block;
    width: 2.5em;
    height: 2.5em;
    cursor: pointer;
    background-image: var(--theme-icon);
    background-size: contain;
    opacity: 0.25;
}

#theme-icon:hover,
#theme-icon:focus {
    opacity: 1;
}
  </style>
  <style>
@media (prefers-color-scheme: light) {
h-[data-h^=err] { color:#ff0000; }
h-[data-h^=cmt] { color:green; font-style:italic; }
h-[data-h^=cmt_dlim] { font-style:normal; }
h-[data-h^=val] { color:#9f6807; }
h-[data-h^=num] { color:#9f6807; }
h-[data-h^=str] { color:#9f6807; }
h-[data-h^=esc] { color:#9f6807; }
h-[data-h^=null] { color:#00607c; }
h-[data-h^=bool] { color:#9f6807; }
h-[data-h^=this] { color:#00607c; }
h-[data-h^=mac] { color:#6f4e37; }
h-[data-h^=id] { color:#000000; }
h-[data-h^=id_labl] { color:#517a0b; }
h-[data-h^=kw] { color:#00607c; }
h-[data-h^=sym] { color:#570057; }
h-[data-h^=sym_punc] { color:#000000; }
h-[data-h^=sym_par] { color:#af1915; }
h-[data-h^=sym_sqr] { color:#af1915; }
h-[data-h^=sym_brac] { color:#af1915; }
h-[data-h^=diff_head] { color:#777777; }
h-[data-h^=diff_head_hunk] { color:#5c477e; }
h-[data-h^=diff_eq] { color:#000000; }
h-[data-h^=diff_del] { color:#b31d28; background-color:#ffeef0; }
h-[data-h^=diff_ins] { color:#22863a; background-color:#f0fff4; }
h-[data-h^=diff_mod] { color:#7a680d; background-color:#fffdee; }
h-[data-h^=mk_tag] { color:#00607c; }
h-[data-h^=mk_attr] { color:#5c477e; }
h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
h-[data-h^=mk_emph] { font-style:italic; }
h-[data-h^=mk_stro] { font-weight:bold; }
h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
h-[data-h^=mk_ulin] { text-decoration:underline; }
h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
h-[data-h^=mk_strk] { text-decoration:line-through; }
h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
h-[data-h^=sh_cmd] { color:#00607c; }
h-[data-h^=sh-opt] { color:#000000; }
h-[data-h^=asm_ins] { color:#00607c; }
h-[data-h^=asm_ins_psu] { color:#9f6807; }
}
@media (prefers-color-scheme: dark) {
h-[data-h^=err] { color:#ff0000; }
h-[data-h^=cmt] { color:#a2e08d; font-style:italic; }
h-[data-h^=cmt_dlim] { font-style:normal; }
h-[data-h^=val] { color:#f2d18d; }
h-[data-h^=num] { color:#f2d18d; }
h-[data-h^=num_dlim] { color:#e6b191; }
h-[data-h^=num_deco] { color:#e6b191; }
h-[data-h^=str] { color:#f2d18d; }
h-[data-h^=str_dlim] { color:#e6b191; }
h-[data-h^=str_deco] { color:#e6b191; }
h-[data-h^=esc] { color:#e6aee6; }
h-[data-h^=null] { color:#62ded6; }
h-[data-h^=bool] { color:#f2d18d; }
h-[data-h^=this] { color:#62ded6; }
h-[data-h^=mac] { color:#cc946e; }
h-[data-h^=id] { color:#f0f0f0; }
h-[data-h^=id_labl] { color:#d8eda6; }
h-[data-h^=kw] { color:#62ded6; }
h-[data-h^=sym] { color:#baa6b9; }
h-[data-h^=sym_punc] { color:#d0d0d0; }
h-[data-h^=sym_par] { color:#fa7878; }
h-[data-h^=sym_sqr] { color:#fa7878; }
h-[data-h^=sym_brac] { color:#fa7878; }
h-[data-h^=diff_head] { color:#777777; }
h-[data-h^=diff_head_hunk] { color:#edc385; }
h-[data-h^=diff_eq] { color:#e7e7e7; }
h-[data-h^=diff_del] { color:#ffdcd7; background-color:#67060c; }
h-[data-h^=diff_ins] { color:#aff5b4; background-color:#033a16; }
h-[data-h^=diff_mod] { color:#fff4d7; background-color:#674d06; }
h-[data-h^=mk_tag] { color:#62ded6; }
h-[data-h^=mk_attr] { color:#a4c4de; }
h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
h-[data-h^=mk_emph] { font-style:italic; }
h-[data-h^=mk_stro] { font-weight:bold; }
h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
h-[data-h^=mk_ulin] { text-decoration:underline; }
h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
h-[data-h^=mk_strk] { text-decoration:line-through; }
h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
h-[data-h^=sh_cmd] { color:#62ded6; }
h-[data-h^=sh-opt] { color:#f0f0f0; }
h-[data-h^=asm_ins] { color:#62ded6; }
h-[data-h^=asm_ins_psu] { color:#e6aee6; }
}

html.light h-[data-h^=err] { color:#ff0000; }
html.light h-[data-h^=cmt] { color:green; font-style:italic; }
html.light h-[data-h^=cmt_dlim] { font-style:normal; }
html.light h-[data-h^=val] { color:#9f6807; }
html.light h-[data-h^=num] { color:#9f6807; }
html.light h-[data-h^=str] { color:#9f6807; }
html.light h-[data-h^=esc] { color:#9f6807; }
html.light h-[data-h^=null] { color:#00607c; }
html.light h-[data-h^=bool] { color:#9f6807; }
html.light h-[data-h^=this] { color:#00607c; }
html.light h-[data-h^=mac] { color:#6f4e37; }
html.light h-[data-h^=id] { color:#000000; }
html.light h-[data-h^=id_labl] { color:#517a0b; }
html.light h-[data-h^=kw] { color:#00607c; }
html.light h-[data-h^=sym] { color:#570057; }
html.light h-[data-h^=sym_punc] { color:#000000; }
html.light h-[data-h^=sym_par] { color:#af1915; }
html.light h-[data-h^=sym_sqr] { color:#af1915; }
html.light h-[data-h^=sym_brac] { color:#af1915; }
html.light h-[data-h^=diff_head] { color:#777777; }
html.light h-[data-h^=diff_head_hunk] { color:#5c477e; }
html.light h-[data-h^=diff_eq] { color:#000000; }
html.light h-[data-h^=diff_del] { color:#b31d28; background-color:#ffeef0; }
html.light h-[data-h^=diff_ins] { color:#22863a; background-color:#f0fff4; }
html.light h-[data-h^=diff_mod] { color:#7a680d; background-color:#fffdee; }
html.light h-[data-h^=mk_tag] { color:#00607c; }
html.light h-[data-h^=mk_attr] { color:#5c477e; }
html.light h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
html.light h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
html.light h-[data-h^=mk_emph] { font-style:italic; }
html.light h-[data-h^=mk_stro] { font-weight:bold; }
html.light h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
html.light h-[data-h^=mk_ulin] { text-decoration:underline; }
html.light h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
html.light h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
html.light h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
html.light h-[data-h^=mk_strk] { text-decoration:line-through; }
html.light h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
html.light h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
html.light h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
html.light h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
html.light h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
html.light h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
html.light h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
html.light h-[data-h^=sh_cmd] { color:#00607c; }
html.light h-[data-h^=sh-opt] { color:#000000; }
html.light h-[data-h^=asm_ins] { color:#00607c; }
html.light h-[data-h^=asm_ins_psu] { color:#9f6807; }

html.dark h-[data-h^=err] { color:#ff0000; }
html.dark h-[data-h^=cmt] { color:#a2e08d; font-style:italic; }
html.dark h-[data-h^=cmt_dlim] { font-style:normal; }
html.dark h-[data-h^=val] { color:#f2d18d; }
html.dark h-[data-h^=num] { color:#f2d18d; }
html.dark h-[data-h^=num_dlim] { color:#e6b191; }
html.dark h-[data-h^=num_deco] { color:#e6b191; }
html.dark h-[data-h^=str] { color:#f2d18d; }
html.dark h-[data-h^=str_dlim] { color:#e6b191; }
html.dark h-[data-h^=str_deco] { color:#e6b191; }
html.dark h-[data-h^=esc] { color:#e6aee6; }
html.dark h-[data-h^=null] { color:#62ded6; }
html.dark h-[data-h^=bool] { color:#f2d18d; }
html.dark h-[data-h^=this] { color:#62ded6; }
html.dark h-[data-h^=mac] { color:#cc946e; }
html.dark h-[data-h^=id] { color:#f0f0f0; }
html.dark h-[data-h^=id_labl] { color:#d8eda6; }
html.dark h-[data-h^=kw] { color:#62ded6; }
html.dark h-[data-h^=sym] { color:#baa6b9; }
html.dark h-[data-h^=sym_punc] { color:#d0d0d0; }
html.dark h-[data-h^=sym_par] { color:#fa7878; }
html.dark h-[data-h^=sym_sqr] { color:#fa7878; }
html.dark h-[data-h^=sym_brac] { color:#fa7878; }
html.dark h-[data-h^=diff_head] { color:#777777; }
html.dark h-[data-h^=diff_head_hunk] { color:#edc385; }
html.dark h-[data-h^=diff_eq] { color:#e7e7e7; }
html.dark h-[data-h^=diff_del] { color:#ffdcd7; background-color:#67060c; }
html.dark h-[data-h^=diff_ins] { color:#aff5b4; background-color:#033a16; }
html.dark h-[data-h^=diff_mod] { color:#fff4d7; background-color:#674d06; }
html.dark h-[data-h^=mk_tag] { color:#62ded6; }
html.dark h-[data-h^=mk_attr] { color:#a4c4de; }
html.dark h-[data-h^=mk_del] { color:#ce9178; text-decoration:line-through; }
html.dark h-[data-h^=mk_ins] { color:#b5cea8; text-decoration:underline; }
html.dark h-[data-h^=mk_emph] { font-style:italic; }
html.dark h-[data-h^=mk_stro] { font-weight:bold; }
html.dark h-[data-h^=mk_emph_stro] { font-style:italic; font-weight:bold; }
html.dark h-[data-h^=mk_ulin] { text-decoration:underline; }
html.dark h-[data-h^=mk_emph_ulin] { font-style:italic; text-decoration:underline; }
html.dark h-[data-h^=mk_stro_ulin] { font-weight:bold; text-decoration:underline; }
html.dark h-[data-h^=mk_emph_stro_ulin] { font-weight:bold; font-style:italic; text-decoration:underline; }
html.dark h-[data-h^=mk_strk] { text-decoration:line-through; }
html.dark h-[data-h^=mk_emph_strk] { font-style:italic; text-decoration:line-through; }
html.dark h-[data-h^=mk_stro_strk] { font-weight:bold; text-decoration:line-through; }
html.dark h-[data-h^=mk_emph_stro_strk] { font-weight:bold; font-style:italic; text-decoration:line-through; }
html.dark h-[data-h^=mk_ulin_strk] { text-decoration:underline line-through; }
html.dark h-[data-h^=mk_emph_ulin_strk] { font-style:italic; text-decoration:underline line-through; }
html.dark h-[data-h^=mk_stro_ulin_strk] { font-weight:bold; text-decoration:underline line-through; }
html.dark h-[data-h^=mk_emph_stro_ulin_strk] { font-weight:bold; font-style:italic; text-decoration:underline line-through; }
html.dark h-[data-h^=sh_cmd] { color:#62ded6; }
html.dark h-[data-h^=sh-opt] { color:#f0f0f0; }
html.dark h-[data-h^=asm_ins] { color:#62ded6; }
html.dark h-[data-h^=asm_ins_psu] { color:#e6aee6; }
  </style>
  <script>
const theme = localStorage.getItem("cowel-theme");
if (theme !== null) {
    document.documentElement.className = theme;
}
  </script>
<title>Better shifting</title></head>
<body>
<div id=settings tabindex=0>
    <div id=theme-icon></div>
    <script>
        const settings = document.getElementById("settings");
        const htmlClasses = document.documentElement.classList;
        const themeIcon = document.getElementById("theme-icon");

        settings.classList.add("js");
        themeIcon.onclick = () => {
            const prefersDark = window.matchMedia("(prefers-color-scheme: dark)");
            const overrideClass = prefersDark.matches ? "light" : "dark";
            if (htmlClasses.contains("light")) {
                htmlClasses.remove("light");
                localStorage.removeItem("cowel-theme");
            } else if (htmlClasses.contains("dark")) {
                htmlClasses.remove("dark");
                localStorage.removeItem("cowel-theme");
            } else {
                htmlClasses.add(overrideClass);
                // to avoid legal issues or controversy in general,
                // we don't mess with local storage when the page is hosted in arbitrary places
                if (window.location.protocol === "file:") {
                    localStorage.setItem("cowel-theme", overrideClass);
                }
            }
        };
        settings.onkeydown = (e) => {
            if (e.key === "Enter" || e.key === " ") {
                event.preventDefault();
                themeIcon.onclick();
            }
        };
    </script>
</div>
<main>
<style>
  ins-block .para::before {
    display: none;
  }

  .stable-ref {
    float: right;
  }

  .five-way-poll {
    table-layout: fixed;
  }
  .five-way-poll td {
    width: 20%;
    text-align: center;
  }
</style>

<p><div class=wg21-head><h1>Better shifting</h1>

<dl>
  <dt>Document number:</dt> <dd><a href=https://wg21%2elink/P3793R0>P3793R0</a></dd>
  <dt>Date:</dt>            <dd><tt->2025-07-15</tt-></dd>
  <dt>Audience:</dt>        <dd>SG6</dd>
  <dt>Project:</dt>         <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21</dd>
  <dt>Reply-to:</dt>        <dd>Brian Bi &lt;<a href=mailto:bbi5291@gmail%2ecom class=sans>bbi5291@gmail.com</a>&gt;</dd>
  <dt>Co-authors:</dt>      <dd>Jan Schultke &lt;<a href=mailto:janschultke@gmail%2ecom class=sans>janschultke@gmail.com</a>&gt;</dd>
  <dt>GitHub Issue:</dt>    <dd><a href=https://wg21%2elink/P3793/github class=sans>wg21.link/P3793/github</a></dd>
  <dt>Source:</dt>          <dd><a href=https://github%2ecom/Eisenwave/cpp-proposals/blob/master/src/better-shifting%2ecow class=sans>github.com/Eisenwave/cpp-proposals/blob/master/src/better-shifting.cow</a></dd>
</dl>
<hr/>
</div></p>

<abstract-block><p><intro-></intro-> 
We propose the addition of functions to the <code><h- data-h=str>&lt;bit&gt;</h-></code> header
to perform bit shifts on integer operands.
The <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-></code> functions provide the
following advantages over the built-in shift operators:
</p>
<ol>
  <li>They always produce a mathematically correct result when possible.</li>
  <li>They never have undefined behavior.</li>
  <li>They avoid the confusing precedence of the built-in shift operators.</li>
</ol>
</abstract-block>

<h2 id=contents><a class=para href=#contents></a>Contents</h2>

<div class=toc><div class=toc-num data-level=2>1</div>
<a href=#introduction><h2>Introduction</h2></a>
<div class=toc-num data-level=2>2</div>
<a href=#motivation><h2>Motivation — Why are overlong shifts needed?</h2></a>
<div class=toc-num data-level=2>3</div>
<a href=#design-considerations><h2>Design considerations</h2></a>
<div class=toc-num data-level=3>3.1</div>
<a href=#proposed-behavior-for-overlong-shifts><h3>Proposed behavior for overlong shifts</h3></a>
<div class=toc-num data-level=4>3.1.1</div>
<a href=#wrapping-behavior-is-not-useful><h4>Wrapping behavior is not useful</h4></a>
<div class=toc-num data-level=4>3.1.2</div>
<a href=#shift-amounts-which-are-overlong-by-more-than-one-should-be-safe><h4>Shift amounts which are overlong by more than one should be safe</h4></a>
<div class=toc-num data-level=3>3.2</div>
<a href=#logical-versus-arithmetic-shifts><h3>Logical versus arithmetic shifts</h3></a>
<div class=toc-num data-level=3>3.3</div>
<a href=#negative-shift-amounts><h3>Negative shift amounts</h3></a>
<div class=toc-num data-level=4>3.3.1</div>
<a href=#why-no-shift-in-the-other-direction><h4>Why no shift in the other direction?</h4></a>
<div class=toc-num data-level=4>3.3.2</div>
<a href=#why-no-unspecified-result><h4>Why no unspecified result?</h4></a>
<div class=toc-num data-level=4>3.3.3</div>
<a href=#why-no-undefined-behavior><h4>Why no undefined behavior?</h4></a>
<div class=toc-num data-level=4>3.3.4</div>
<a href=#conclusion><h4>Conclusion</h4></a>
<div class=toc-num data-level=3>3.4</div>
<a href=#naming><h3>Naming</h3></a>
<div class=toc-num data-level=3>3.5</div>
<a href=#signatures><h3>Signatures</h3></a>
<div class=toc-num data-level=3>3.6</div>
<a href=#simd-support><h3>SIMD support</h3></a>
<div class=toc-num data-level=2>4</div>
<a href=#wording><h2>Wording</h2></a>
<div class=toc-num data-level=3>4.1</div>
<a href=#version%2esyn><h3>[version.syn]</h3></a>
<div class=toc-num data-level=3>4.2</div>
<a href=#bit><h3>[bit]</h3></a>
<div class=toc-num data-level=3>4.3</div>
<a href=#simd><h3>[simd]</h3></a>
<div class=toc-num data-level=2>5</div>
<a href=#references><h2>References</h2></a>
</div>

<h2 id=introduction><a class=para href=#introduction></a>1. Introduction</h2>

<p>C++ has built-in shift operators, <code><h- data-h=sym_op>&lt;&lt;</h-></code> and <code><h- data-h=sym_op>&gt;&gt;</h-></code>,
inherited from C with semantics essentially unchanged,
including the following two inconvenient properties:
</p>
<ol>
  <li>
    The precedence of these operators is less than the precedence of the additive operators,
    which is counterintuitive because shift operations
    behave as multiplication and division by a power of 2.
  </li>
  <li>
    If the shift amount is greater than or equal to the width of the (promoted)
    left operand or is negative, the behavior is undefined.
    In the remainder of this document,
    we will refer to shifts by a positive amount that is greater than
    or equal to the bit width of the operand as <dfn>overlong</dfn> shifts.
  </li>
</ol>

<p>The first property certainly cannot be changed at this point in time.
Reflector discussion revealed that GCC relies on the second property when vectorizing
multiple shift operations on adjacent memory locations,
and changing it might therefore not be "free".
Besides that, changing the second property is also likely to be contentious
because some committee members prefer to make overlong
shifts erroneous behavior instead of defining them to produce the mathematically
correct result.
</p>
<p>For these reasons, we are instead proposing to solve the problems with shifting in C++
by introducing new Standard Library facilities in the <code><h- data-h=str>&lt;bit&gt;</h-></code> header.
</p>
<h2 id=motivation><a class=para href=#motivation></a>2. Motivation — Why are overlong shifts needed?</h2>

<p>We consider the undefined behavior of overlong shifts to be gratuitous.
Unlike other arithmetic operators, which produce undefined behavior only when the result is
"not mathematically defined or is outside the range of representable values" (<a href=https://eel%2eis/c++draft/expr%2epre#4>[expr.pre] paragraph 4</a>),
the built-in shift operators unconditionally produce UB for overlong shifts.
This behavior is inherited from C,
in which the arithmetic operators were originally designed to do
whatever the corresponding hardware instructions would do;
processor families differ as to how overlong shifts are
handled.
However, it is unclear why the behavior of overlong shifts was
standardized as being undefined behavior as opposed to producing an unspecified result;
perhaps there's some CPU that we (the authors of this paper)
don't know about (and that might even be obsolete)
on which the behavior could include trapping, halting, or otherwise failing to produce a result.
</p>
<p>Besides that, there are practical reasons why the undefined behavior of overlong
shifts is inconvenient, particularly when the second operand is equal to the bit
width of the first operand.
</p>
<example-block><p><intro-></intro-> 
Consider the task of implementing the following function:
</p>
<code-block><h- data-h=cmt_dlim>//</h-><h- data-h=cmt>/ </h-><f-serif><h- data-h=cmt>Return the value of </h-><code><h- data-h=id>x</h-></code><h- data-h=cmt> with the least significant </h-><code><h- data-h=id>num_bits</h-></code><h- data-h=cmt> bits masked out.</h-></f-serif>
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt>/ </h-><f-serif><code><h- data-h=id>num_bits</h-></code><h- data-h=cmt> shall be nonnegative and </h-><h- data-h=cmt>≤</h-><h- data-h=cmt> </h-><code><h- data-h=num>32</h-></code><h- data-h=cmt>.</h-></f-serif>
<h- data-h=kw_type>unsigned</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-> <h- data-h=id>mask_lsb</h-><h- data-h=sym_par>(</h-><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>num_bits</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>When <code><h- data-h=id>num_bits</h-></code> is equal to 32, the behavior of <code><h- data-h=id>mask_lsb</h-></code> is the natural
continuation of the behavior for smaller values of num_bits.
However, to implement this function,
we must guard against <code><h- data-h=id>num_bits</h-> <h- data-h=sym_op>==</h-> <h- data-h=num>32</h-></code>:
</p>
<code-block><h- data-h=kw_type>unsigned</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-> <h- data-h=id>mask_lsb</h-><h- data-h=sym_par>(</h-><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>num_bits</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=id>num_bits</h-> <h- data-h=sym_op>==</h-> <h- data-h=num>32</h-><h- data-h=sym_par>)</h-> <h- data-h=kw_ctrl>return</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>;</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=id>x</h-> <h- data-h=sym_op>&amp;</h-> <h- data-h=sym_op>~</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=num>1</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;&lt;</h-> <h- data-h=id>num_bits</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>-</h-> <h- data-h=num>1</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>

<p>The first statement in the body of <code><h- data-h=id>mask_lsb</h-></code> would be unnecessary
if the shift operation produced the mathematically correct result of <code><h- data-h=num>0</h-></code>
when <code><h- data-h=id>num_bits</h-></code> is equal to <code><h- data-h=num>32</h-></code>.
</p></example-block>

<p>Overlong bit-shifts can also be a problem with right-shifting,
although these problems are significantly less common.
</p>
<example-block><p><intro-></intro-> 
We can use an integer <code><h- data-h=id>b</h-></code> to represent a bitset,
where <code><h- data-h=num>1</h-></code> represents an element which is in the set,
and <code><h- data-h=num>0</h-></code> represents an integer that does not.
</p>
<code-block><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id_type>uint32_t</h-> <h- data-h=id>bitset</h-> <h- data-h=sym_op>=</h-> <h- data-h=cmt_dlim>/*</h-><h- data-h=cmt> ... </h-><h- data-h=cmt_dlim>*/</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>Possibly undefined behavior; would require special cases to guard against overlong shifts.</h-></f-serif>
<h- data-h=kw_type>bool</h-> <h- data-h=id>contains</h-><h- data-h=sym_par>(</h-><h- data-h=id_type>size_t</h-> <h- data-h=id>i</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=sym_par>(</h-><h- data-h=id>bitset</h-> <h- data-h=sym_op>&gt;&gt;</h-> <h- data-h=id>i</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&amp;</h-> <h- data-h=num>1</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>Never undefined.</h-></f-serif>
<h- data-h=kw_type>bool</h-> <h- data-h=id>contains</h-><h- data-h=sym_par>(</h-><h- data-h=id_type>size_t</h-> <h- data-h=id>i</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=id>bitset</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-><h- data-h=sym_par>(</h-><h- data-h=id>i</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&amp;</h-> <h- data-h=num>1</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>

<p>Reporting an element that <code><h- data-h=id>bitset</h-></code> has no capacity for
as not being in the set may be exactly the behavior we want, rather than UB,
and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-></code> makes that easy.
</p></example-block>

<h2 id=design-considerations><a class=para href=#design-considerations></a>3. Design considerations</h2>

<h3 id=proposed-behavior-for-overlong-shifts><a class=para href=#proposed-behavior-for-overlong-shifts></a>3.1. Proposed behavior for overlong shifts</h3>

<p>We propose the addition of Standard Library functions
<code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-></code>
that produce mathematically correct results for overlong shifts.
That is, these functions actually just shift the bits by the number of positions specified:
in the case of an overlong shift, that means that all bits that would
be shifted are shifted off the end.
For a logical shift, the result is <code><h- data-h=num>0</h-></code>;
for an arithmetic right shift,
the result is <code><h- data-h=sym_op>-</h-><h- data-h=num>1</h-></code> when the first operand is negative, and <code><h- data-h=num>0</h-></code> otherwise.
</p>
<h4 id=wrapping-behavior-is-not-useful><a class=para href=#wrapping-behavior-is-not-useful></a>3.1.1. Wrapping behavior is not useful</h4>

<p>We believe that the "wrapping" behavior
(most famously exhibited by the x86 family of processors)
in which the shift amount is reduced modulo the bit width
of the other operand is not useful,
other than when implementing bit rotations.
Since the functions <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code>
are already provided by the Standard
Library, C++ programmers do not need to implement rotations themselves anymore,
and would not benefit from wrapping behavior for shifts.
</p>
<h4 id=shift-amounts-which-are-overlong-by-more-than-one-should-be-safe><a class=para href=#shift-amounts-which-are-overlong-by-more-than-one-should-be-safe></a>3.1.2. Shift amounts which are overlong by more than one should be safe</h4>

<p>Although shifts by an amount that are strictly greater than the bit width of the
first operand are not as useful as when the amount is equal to the bit width,
we believe that requiring the implementation to produce the mathematically correct
result in those cases does not impose an additional performance burden.
For example, if <code><h- data-h=id>x</h-></code> is <code><h- data-h=num>32</h-></code> bits wide,
then requiring <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shift_left</h-><h- data-h=sym_par>(</h-><h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>33</h-><h- data-h=sym_par>)</h-></code> to produce <code><h- data-h=num>0</h-></code>
does not impose additional overhead
beyond only requiring <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shift_left</h-><h- data-h=sym_par>(</h-><h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>32</h-><h- data-h=sym_par>)</h-></code> to
produce <code><h- data-h=num>0</h-></code>.
</p>
<example-block><p><intro-></intro-> 
For example, GCC 15.1 at <tt->-O2</tt-> or higher produces very similar x86-64
assembly for the following two functions:
</p>
<code-block><h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>shl1</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>amount</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=id>amount</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=num>32</h-><h- data-h=sym_par>)</h-> <h- data-h=kw_ctrl>return</h-> <h- data-h=id>x</h-> <h- data-h=sym_op>&lt;&lt;</h-> <h- data-h=id>amount</h-><h- data-h=sym_punc>;</h-> <h- data-h=kw_ctrl>else</h-> <h- data-h=kw_ctrl>return</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h->
<h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>shl2</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>amount</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=id>amount</h-> <h- data-h=sym_op>&gt;</h-> <h- data-h=num>32</h-><h- data-h=sym_par>)</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>unreachable</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
    <h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=id>amount</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=num>32</h-><h- data-h=sym_par>)</h-> <h- data-h=kw_ctrl>return</h-> <h- data-h=id>x</h-> <h- data-h=sym_op>&lt;&lt;</h-> <h- data-h=id>amount</h-><h- data-h=sym_punc>;</h-> <h- data-h=kw_ctrl>else</h-> <h- data-h=kw_ctrl>return</h-> <h- data-h=num>0</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>

<code-block><h- data-h=id_labl_decl>shl1:</h->
        <h- data-h=asm_ins>mov</h->     <h- data-h=id_var>ecx</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>esi</h->
        <h- data-h=asm_ins>xor</h->     <h- data-h=id_var>eax</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>eax</h->
        <h- data-h=asm_ins>sal</h->     <h- data-h=id_var>edi</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>cl</h->
        <h- data-h=asm_ins>cmp</h->     <h- data-h=id_var>esi</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>32</h->
        <h- data-h=asm_ins>cmovb</h->   <h- data-h=id_var>eax</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>edi</h->
        <h- data-h=asm_ins>ret</h->
<h- data-h=id_labl_decl>shl2:</h->
        <h- data-h=asm_ins>mov</h->     <h- data-h=id_var>ecx</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>esi</h->
        <h- data-h=asm_ins>xor</h->     <h- data-h=id_var>eax</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>eax</h->
        <h- data-h=asm_ins>sal</h->     <h- data-h=id_var>edi</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>cl</h->
        <h- data-h=asm_ins>cmp</h->     <h- data-h=id_var>esi</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>32</h->
        <h- data-h=asm_ins>cmovne</h->  <h- data-h=id_var>eax</h-><h- data-h=sym_punc>,</h-> <h- data-h=id_var>edi</h->
        <h- data-h=asm_ins>ret</h-></code-block>

<p>Using <code><h- data-h=id>shl2</h-></code> instead of <code><h- data-h=id>shl1</h-></code> can improve performance
only in the sense that UB enables more optimizations in general
(e.g. assuming that the branch leading to the UB is not taken).
The generated code in Clang 20 is very similar.
</p></example-block>

<p>Such similarities in generated assembly are observed across many other architectures
because if a single branch or conditional move instruction is
required in order to produce the mathematically correct result for amount <code><h- data-h=sym_op>&gt;=</h-> <h- data-h=num>32</h-></code>,
then a single one will also be needed merely to account for the case of
<code><h- data-h=id>amount</h-> <h- data-h=sym_op>==</h-> <h- data-h=num>32</h-></code> (when <code><h- data-h=id>amount</h-> <h- data-h=sym_op>&gt;</h-> <h- data-h=num>32</h-></code> is disallowed).
</p>
<h3 id=logical-versus-arithmetic-shifts><a class=para href=#logical-versus-arithmetic-shifts></a>3.2. Logical versus arithmetic shifts</h3>

<p>The built-in <code><h- data-h=sym_op>&gt;&gt;</h-></code> operator performs an arithmetic shift on signed operands:
that is, the sign bit is extended.
One possible design is to provide both arithmetic and logical right shifts,
either as separate functions or as one function with
an additional parameter indicating the choice of arithmetic or logical shift.
</p>
<p>However, we believe that this is unnecessary because in cases where the
programmer wishes to always perform a logical shift,
it is customary to employ unsigned types,
possibly by inserting a cast that will be optimized out.
Conversely, the deliberate choice to use a signed type for the left operand of
a right shift indicates intent to perform an arithmetic shift.
The proposed <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>to_signed</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>to_unsigned</h-></code>
functions in <a href="https://wg21%2elink/p3643r0">[P3643R0]</a> would make such conversions convenient,
even in generic code.
</p>
<p>A survey of popular programming languages supports this design direction:
</p>
<ul>
  <li>
    Languages that provide an explicit choice between a logical shift or an
    arithmetic shift usually lack unsigned integer types
    (Fortran, Java, JavaScript, OCaml).
    C# had unsigned integer types from its initial release, but
    didn't have the logical right shift operator until version 11.
  </li>
  <li>
    Languages that do not provide an explicit choice between a logical shift and
    an arithmetic shift always perform arithmetic shifts for negative operands
    (Go, Haskell, Objective-C, Python, Ruby, Rust).
  </li>
  <li>
    Perl is possibly an exception to the above,
    but it is hard to track down the behavior of shifts prior to version 5.
  </li>
</ul>

<h3 id=negative-shift-amounts><a class=para href=#negative-shift-amounts></a>3.3. Negative shift amounts</h3>

<p>The behavior of negative shift amounts
in some popular programming languages is listed below:
</p>
<ul>
<li>Shift amount reduced modulo bit width of other operand: C#, Java, JavaScript</li>
<li>Exception or panic: Go, Haskell, Python</li>
<li>Shift in other direction: Fortran, Objective-C, Perl, Ruby</li>
<li>Unspecified or implementation-defined result: OCaml, Rust</li>
</ul>

<p>Unlike overlong shifts, there is no obvious "mathematically correct result"
for a shift by a negative number of bits,
nor is there an obvious choice based on existing practice in other programming languages.
Hardware instructions interpret the shift amount as an unsigned number.
</p>
<p>There are several options for how the proposed <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shl</h-></code> and
<code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-></code> functions could handle negative shift widths:
</p><ol>
  <li>Shift in other direction.</li>
  <li>Implementation-defined result.</li>
  <li>Erroneous behavior with implementation-defined result (proposed).</li>
  <li>Unspecified result.</li>
  <li>Erroneous behavior with unspecified result.</li>
  <li>Undefined behavior.</li>
</ol>

<h4 id=why-no-shift-in-the-other-direction><a class=para href=#why-no-shift-in-the-other-direction></a>3.3.1. Why no shift in the other direction?</h4>

<p>The first option imposes performance overhead compared with only handling
overlong shifts, which makes the second and third options more attractive.
Use cases where we want to shift in the other direction are extremely uncommon,
and in those uncommon use cases,
these operations can be easily expressed by conditionally shifting to the left or right.
</p>
<h4 id=why-no-unspecified-result><a class=para href=#why-no-unspecified-result></a>3.3.2. Why no unspecified result?</h4>

<p>Hardware architectures don't always guarantee a specific result for
bit-shifting instructions.
For example, older Intel x86-64 processors do not guarantee that shifting wraps,
but yield an unspecified result.
Therefore, it might seem at first that requiring a predictable,
implementation-defined result imposes additional overhead compared with leaving
the result unspecified.
However, all hardware that we are aware of treats the shift amount as an
unsigned integer: that is, any attempt to shift by a negative amount would be
interpreted as an attempt to shift by a large positive amount congruent to the
original negative amount. Since we already propose to require shifting by large
positive amounts to produce a defined result, an implementation could simply
define negative shifts to produce the same result as overlong shifts without
incurring an additional performance penalty:
</p>
<code-block><h- data-h=kw_type>unsigned</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>unsigned</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>Handles negative, not just over-large shifts, at no extra cost.</h-></f-serif>
  <h- data-h=kw_ctrl>return</h-> <h- data-h=kw_type>unsigned</h-><h- data-h=sym_par>(</h-><h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <i><h- data-h=id>width-v</h-></i><h- data-h=sym_op>&lt;</h-><h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=sym_op>?</h-> <h- data-h=num>0</h-><h- data-h=num_deco>u</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>x</h-> <h- data-h=sym_op>&gt;&gt;</h-> <h- data-h=id>s</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>

<h4 id=why-no-undefined-behavior><a class=para href=#why-no-undefined-behavior></a>3.3.3. Why no undefined behavior?</h4>

<p>Unlike division by zero,
there is little motivation to make this operation undefined;
the underlying hardware instruction does not raise an exception,
but produces a surprising (possibly unspecified) result.
</p>
<p>If the programmer wants shifting by a negative amount <code><h- data-h=id>s</h-></code> to have undefined behavior,
they can opt into that using:
</p><code-block><h- data-h=kw_ctrl>if</h-> <h- data-h=sym_par>(</h-><h- data-h=id>s</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=num>0</h-><h- data-h=sym_par>)</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>unreachable</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>or</h-></f-serif>
<h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>[</h-><h- data-h=id>assume</h-><h- data-h=sym_par>(</h-><h- data-h=id>s</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=num>0</h-><h- data-h=sym_par>)</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_punc>;</h-></code-block>

<h4 id=conclusion><a class=para href=#conclusion></a>3.3.4. Conclusion</h4>

<p>Attempting to shift by a negative amount is often a bug,
with the programmer's intent being unclear.
However, there is no necessity for undefined behavior.
</p>
<p>Therefore, we propose the third option (erroneous behavior with implementation-defined result).
</p>
<h3 id=naming><a class=para href=#naming></a>3.4. Naming</h3>

<p>We chose the names <code><h- data-h=id>shl</h-></code> and <code><h- data-h=id>shr</h-></code>
because they are as short as possible,
while still being familiar to many programmers.
For example, the x86 and ARM instruction sets
have shift instructions named <code><h- data-h=id>SHL</h-></code> and <code><h- data-h=id>SHR</h-></code>,
Pascal has built-in operators with these names,
and Rust uses <code><h- data-h=id>Shl</h-></code> and <code><h- data-h=id>Shr</h-></code> as the names of the traits
that must be implemented for types to support the shift operators.
</p>
<p>We hope the brevity will encourage adoption of <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-></code>
as safe alternatives to the built-in operators.
These abbreviations are also consistent
with the existing <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code> functions,
which are conspicuously not named <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotate_left</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotate_right</h-></code>,
respectively.
</p>

<h3 id=signatures><a class=para href=#signatures></a>3.5. Signatures</h3>

<p>We propose the following signatures:
</p>
<code-block><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>

<p>The rationale for these signature is as follows:
</p>
<ul>
  <li>
    We follow the design of <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code>
    in proposing that the shift functions do not perform integer promotion.
  </li>
  <li>
    Like <code><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>rotr</h-></code>,
    these functions don't participate in overload resolution
    unless <code><h- data-h=id>T</h-></code> is an integer type.
    Unlike <code><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>rotr</h-></code>, the proposed <code><h- data-h=id>shl</h-></code> and <code><h- data-h=id>shr</h-></code>
    accept either signed or unsigned integral types for the first operand:
    for <code><h- data-h=id>shr</h-></code>,
    the signedness of the first parameter determines whether an arithmetic or
    logical shift is performed,
    and it would be surprising if <code><h- data-h=id>shl</h-></code> did not also accept signed types.
  </li>
  <li>
    We follow the design of <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code>
    in specifying a type of <code><h- data-h=kw_type>int</h-></code> for the second parameter.
    <code><h- data-h=kw_type>int</h-></code> is large enough to hold any realistic shift width,
    and the choice of a signed type rather than an unsigned type allows the
    implementation to catch bugs in which the expression for the second argument
    produced a negative result.
  </li>
  <li>
    Although the Lakos rule states that Standard Library functions with narrow
    contracts should not be declared noexcept,
    we don't have precedent for functions that never produce undefined behavior
    but produce erroneous behavior for some subset of arguments.
    However, we think that we can sidestep that debate because
    of the precedent that functions that are closely analogous to built-in
    operators that are not potentially-throwing should be declared <code><h- data-h=kw>noexcept</h-></code> even if
    they have narrow contracts.
    If that is the case, it should be even more the
    case for functions that sometimes exhibit erroneous behavior.
  </li>
</ul>

<h3 id=simd-support><a class=para href=#simd-support></a>3.6. SIMD support</h3>

<p>Following <a href="https://wg21%2elink/p2933r4">[P2933R4]</a>,
almost all <code><h- data-h=str>&lt;bit&gt;</h-></code> functions have a corresponding overload in <code><h- data-h=str>&lt;simd&gt;</h-></code>,
including <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code>.
</p>
<p>The proposed functions should also have <code><h- data-h=str>&lt;simd&gt;</h-></code> overloads,
in the style of <code><h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-></code>.
That is, overloads that can either shift a <code><h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>vec</h-></code> by a <code><h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>vec</h-></code>
of shift amounts,
or by a scalar shift amount which applies to all elements in the <code><h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>vec</h-></code>.
</p>
<h2 id=wording><a class=para href=#wording></a>4. Wording</h2>

<p>The following changes are relative to <a href="https://wg21%2elink/n5008">[N5008]</a>.
</p>
<note-block><p><intro-></intro-> 
The <code><h- data-h=id>shl</h-></code> and <code><h- data-h=id>shr</h-></code> functions should immediately precede the
<code><h- data-h=id>rotl</h-></code> and <code><h- data-h=id>rotr</h-></code> functions in the wording. Therefore, if this paper
and <a href="https://wg21%2elink/p3764r0">[P3764R0]</a> are adopted in the same meeting, the <code><h- data-h=id>shl</h-></code> and <code><h- data-h=id>shr</h-></code>
functions should be inserted between the <code><h- data-h=id>msb_to_mask</h-></code> and <code><h- data-h=id>rotl</h-></code>
functions.
</p></note-block>

<h3 id=version.syn><a class=para href=#version%2esyn></a>4.1. [version.syn]</h3>

<p>Bump feature-test macros in <a href=https://eel%2eis/c++draft/version%2esyn>[version.syn]</a> as follows:
</p>
<diff-block>
<code-block class=borderless><h- data-h=mac>#define __cpp_lib_bitops </h-><del><h- data-h=mac>201907L</h-></del><h- data-h=mac> </h-><ins><h- data-h=mac>20XXXXL</h-></ins><h- data-h=mac> </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>freestanding, also in </h-><tt-><h- data-h=cmt>&lt;bit&gt;</h-></tt-></f-serif>
<h- data-h=mac>#define __cpp_lib_simd </h-><del><h- data-h=mac>202502L</h-></del><h- data-h=mac> </h-><ins><h- data-h=mac>20XXXXL</h-></ins><h- data-h=mac>   </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>also in </h-><tt-><h- data-h=cmt>&lt;simd&gt;</h-></tt-></f-serif></code-block>
</diff-block>

<h3 id=bit><a class=para href=#bit></a>4.2. [bit]</h3>

<p>In <a href=https://eel%2eis/c++draft/bit%2esyn>[bit.syn]</a>, change the synopsis as follows:
</p>
<diff-block>
<code-block class=borderless><h- data-h=kw>namespace</h-> <h- data-h=id>std</h-> <h- data-h=sym_brac>{</h->
  […]

<ins>  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>[bit.shift], shifting</h-></f-serif>
  <h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
    <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
    <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></ins>

  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>[bit.rotate], rotating</h-></f-serif>
  <h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
    <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>rotl</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
    <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>rotr</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  […]
<h- data-h=sym_brac>}</h-></code-block>
</diff-block>

<p>In <a href=https://eel%2eis/c++draft/bit>[bit]</a>, add a new subclause immediately preceding <a href=https://eel%2eis/c++draft/bit%2erotate>[bit.rotate]</a>:
</p>
<ins-block>
<h3>Shifting <span class=stable-ref>[bit.shift]</span></h3>

<code-block class=borderless><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>

<div class=indent>
<p><i>Constraints</i>:
<code><h- data-h=id>T</h-></code> is a signed or unsigned integer type (<a href=https://eel%2eis/c++draft/basic%2efundamental>[basic.fundamental]</a>).
</p>
<p><i>Effects</i>:
If <code><h- data-h=id>s</h-></code> is negative, the behavior is erroneous and an
implementation-defined value is returned. Otherwise, returns the value of
<code><h- data-h=id>x</h-></code> multiplied by 2<sup><code><h- data-h=id>s</h-></code></sup>.
<br/><wg21-block>[<i>Note</i>: If <code><h- data-h=id>s</h-></code> is greater than or equal to the bit width of <code><h- data-h=id>T</h-></code>,
the result is zero. — <i>end note</i>]</wg21-block>
</p></div>

<code-block class=borderless><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>T</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>T</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=id>T</h-> <h- data-h=id>x</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>

<div class=indent>
<p><i>Constraints</i>:
<code><h- data-h=id>T</h-></code> is a signed or unsigned integer type (<a href=https://eel%2eis/c++draft/basic%2efundamental>[basic.fundamental]</a>).
</p>
<p><i>Effects</i>:
If <code><h- data-h=id>s</h-></code> is negative, the behavior is erroneous and an
implementation-defined value is returned. Otherwise, returns the value of
<code><h- data-h=id>x</h-></code> divided by 2<sup><code><h- data-h=id>s</h-></code></sup>, rounded toward negative infinity.
<br/><wg21-block>[<i>Note</i>: If <code><h- data-h=id>s</h-></code> is greater than or equal to the bit width of <code><h- data-h=id>T</h-></code>,
the result is -1 if <code><h- data-h=id>x</h-></code> is negative and 0 otherwise; the computation of
2<sup><code><h- data-h=id>s</h-></code></sup> does not overflow. — <i>end note</i>]</wg21-block>
</p></div>
</ins-block>

<h3 id=simd><a class=para href=#simd></a>4.3. [simd]</h3>

<p>In <a href=https://eel%2eis/c++draft/simd%2esyn>[simd.syn]</a>, change the synopsis as follows:
</p>
<diff-block>
<code-block class=borderless>[…]

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>[simd.bit], Bit manipulation</h-></f-serif>

[…]

<ins><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h->  <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h->  <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></ins>

<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>rotl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h->  <h- data-h=id>rotl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>rotr</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h->  <h- data-h=id>rotr</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

[…]

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> See </h-><f-serif><h- data-h=cmt>[simd.bit], Bit manipulation</h-></f-serif>
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>byteswap</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>bit_ceil</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>bit_floor</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>has_single_bit</h-><h- data-h=sym_punc>;</h->
<ins><h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>shl</h-><h- data-h=sym_punc>;</h-></ins>
<ins><h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>shr</h-><h- data-h=sym_punc>;</h-></ins>
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotl</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>rotr</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>bit_width</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>countl_zero</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>countl_one</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>countr_zero</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>countr_one</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>using</h-> <h- data-h=id>simd</h-><h- data-h=sym_op>::</h-><h- data-h=id>popcount</h-><h- data-h=sym_punc>;</h->

[…]</code-block>
</diff-block>

<p>In <a href=https://eel%2eis/c++draft/simd%2ebit>[simd.bit]</a>, immediately preceding the first declaration of
<code><h- data-h=id>rotl</h-></code>, insert the following:
</p>
<ins-block>
<code-block class=borderless><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v0</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v1</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V0</h-><h- data-h=sym_punc>,</h-> <i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V1</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V0</h-> <h- data-h=id>shr</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v0</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v1</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>

<div class=indent>
<p><i>Constraints</i>:
</p><ul>
  <li>The type <code><h- data-h=id>V0</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-></code> is a signed or unsigned integer
      type (<a href=https://eel%2eis/c++draft/basic%2efundamental>[basic.fundamental]</a>),</li>
  <li>the type <code><h- data-h=id>V1</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-></code> models <code><h- data-h=id>integral</h-></code>,</li>
  <li><code><h- data-h=id>V0</h-><h- data-h=sym_op>::</h-><h- data-h=id>size</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>.</h-><h- data-h=id>size</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-></code> is <code><h- data-h=bool>true</h-></code>, and</li>
  <li><code><h- data-h=kw>sizeof</h-><h- data-h=sym_par>(</h-><h- data-h=kw>typename</h-> <h- data-h=id>V0</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=kw>sizeof</h-><h- data-h=sym_par>(</h-><h- data-h=kw>typename</h-> <h- data-h=id>V1</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-><h- data-h=sym_par>)</h-></code>
      is <code><h- data-h=bool>true</h-></code>.</li>
</ul>

<p><i>Returns</i>:
A <code><h- data-h=id>basic_simd</h-></code> object where the <math display=inline><msup><mi>i</mi><mtext>th</mtext></msup></math> element
is initialized to the result of <code><i><h- data-h=id>bit-func</h-></i><h- data-h=sym_par>(</h-><h- data-h=id>v0</h-><h- data-h=sym_sqr>[</h-><math display=inline><mi>i</mi></math><h- data-h=sym_sqr>]</h-><h- data-h=sym_punc>,</h->
<h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>int</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>v1</h-><h- data-h=sym_sqr>[</h-><math display=inline><mi>i</mi></math><h- data-h=sym_sqr>]</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code> for all <math display=inline><mi>i</mi></math> in the range
[<code><h- data-h=num>0</h-></code>, <code><h- data-h=id>V</h-><h- data-h=sym_op>::</h-><h- data-h=id>size</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-></code>), where <code><i><h- data-h=id>bit-func</h-></i></code> has the same
behavior as the corresponding scalar function from <code><h- data-h=str>&lt;bit&gt;</h-></code> except that the
type of its second parameter is considered to be <code><h- data-h=id>V1</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>simd-type</h-></i> <h- data-h=id>V</h-><h- data-h=sym_op>&gt;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=id>V</h-> <h- data-h=id>shl</h-><h- data-h=sym_par>(</h-><h- data-h=kw>const</h-> <h- data-h=id>V</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>v</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>

<div class=indent>
<p><i>Constraints</i>:
The type <code><h- data-h=id>V</h-><h- data-h=sym_op>::</h-><h- data-h=id>value_type</h-></code> is a signed or unsigned integer
type (<a href=https://eel%2eis/c++draft/basic%2efundamental>[basic.fundamental]</a>).
</p>
<p><i>Returns</i>:
A <code><h- data-h=id>basic_simd</h-></code> object where the <math display=inline><msup><mi>i</mi><mtext>th</mtext></msup></math> element is
initialized to the result of <code><i><h- data-h=id>bit-func</h-></i><h- data-h=sym_par>(</h-><h- data-h=id>v</h-><h- data-h=sym_sqr>[</h-><math display=inline><mi>i</mi></math><h- data-h=sym_sqr>]</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>s</h-><h- data-h=sym_par>)</h-></code> for
all <math display=inline><mi>i</mi></math> in the range [<code><h- data-h=num>0</h-></code>, <code><h- data-h=id>V</h-><h- data-h=sym_op>::</h-><h- data-h=id>size</h-><h- data-h=sym_par>(</h-><h- data-h=sym_par>)</h-></code>), where
<code><i><h- data-h=id>bit-func</h-></i></code> is the corresponding scalar function from
<code><h- data-h=str>&lt;bit&gt;</h-></code>.
</p></div>
</ins-block>


<h2 id=references><a class=para href=#references></a>5. References</h2>






<div class=bib><div id=bib-item-N5008 class=bib-item>
<a href="https://wg21%2elink/n5008">[N5008]</a>
<span class=bib-author>Thomas Köppe.</span>
<span class=bib-title>Working Draft, Programming Languages — C++</span>
<span class=bib-date>2025-03-15</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/n5008%2epdf" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/n5008.pdf</a></div><div id=bib-item-P2933R4 class=bib-item>
<a href="https://wg21%2elink/p2933r4">[P2933R4]</a>
<span class=bib-author>Daniel Towner, Ruslan Arutyunyan.</span>
<span class=bib-title>Extend &lt;bit&gt; header function with overloads  for std::simd</span>
<span class=bib-date>2025-02-13</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/p2933r4%2ehtml" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2933r4.html</a></div><div id=bib-item-P3643R0 class=bib-item>
<a href="https://wg21%2elink/p3643r0">[P3643R0]</a>
<span class=bib-author>Jan Schultke.</span>
<span class=bib-title>std::to_signed and std::to_unsigned</span>
<span class=bib-date>2025-03-13</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/p3643r0%2ehtml" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3643r0.html</a></div><div id=bib-item-P3764R0 class=bib-item>
<a href="https://wg21%2elink/p3764r0">[P3764R0]</a>
<span class=bib-author>Jan Schultke.</span>
<span class=bib-title>A utility function for propagating the most significant bit</span>
<span class=bib-date>2025-07-15</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/p3764r0%2ehtml" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3764r0.html</a></div></div>
</main></body>
</html>
