<!DOCTYPE html>
<html>
<head>
  <meta charset=UTF-8 /><meta name=viewport content="width=device-width, initial-scale=1"/><link rel=preconnent href=https://fonts.googleapis.com />
  <link rel=preconnent href=https://fonts.gstatic.com crossorigin/>
  <link rel=stylesheet href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700&family=Noto+Sans:ital,wght@0,100..900;1,100..900&family=Noto+Serif:ital,wght@0,100..900;1,100..900&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>ASCII character utilities</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>
<div class=wg21-head><h1>ASCII character utilities</h1>

<dl>
  <dt>Document number:</dt> <dd><a href=https://wg21.link/P3688>P3688R2</a></dd>
  <dt>Date:</dt>            <dd><tt->2025-08-14</tt-></dd>
  <dt>Audience:</dt>        <dd>SG16</dd>
  <dt>Project:</dt>         <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21</dd>
  <dt>Reply-To:</dt>        <dd>Jan Schultke &lt;<a href=mailto:janschultke@gmail.com class=sans>janschultke@gmail.com</a>&gt;</dd>
  <dt>Co-Authors:</dt>      <dd>Corentin Jabot &lt;<a href=mailto:corentin.jabot@gmail.com class=sans>corentin.jabot@gmail.com</a>&gt;</dd>
  <dt>GitHub Issue:</dt>    <dd><a href=https://wg21.link/P3688/github class=sans>wg21.link/P3688/github</a></dd>
  <dt>Source:</dt>          <dd><a href=https://github.com/Eisenwave/cpp-proposals/blob/master/src/ascii.cow class=sans>github.com/Eisenwave/cpp-proposals/blob/master/src/ascii.cow</a></dd>
</dl>
<hr/>
</div>

<abstract-block><p><intro-></intro-> 
The utilities in <code><h- data-h=str>&lt;cctype&gt;</h-></code> or <code><h- data-h=str>&lt;locale&gt;</h-></code>
are locale-specific,
not <code><h- data-h=kw>constexpr</h-></code>,
and provide no support for Unicode character types.
We propose lightweight, locale-independent alternatives.
</p></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=#revision-history><h2>Revision history</h2></a>
<div class=toc-num data-level=3>1.1</div>
<a href=#changes-since-r1><h3>Changes since R1</h3></a>
<div class=toc-num data-level=3>1.2</div>
<a href=#changes-since-r0><h3>Changes since R0</h3></a>
<div class=toc-num data-level=2>2</div>
<a href=#introduction><h2>Introduction</h2></a>
<div class=toc-num data-level=3>2.1</div>
<a href=#cant-you-implement-this-trivially-yourself><h3>Can't you implement this trivially yourself?</h3></a>
<div class=toc-num data-level=2>3</div>
<a href=#design><h2>Design</h2></a>
<div class=toc-num data-level=3>3.1</div>
<a href=#list-of-proposed-functions><h3>List of proposed functions</h3></a>
<div class=toc-num data-level=3>3.2</div>
<a href=#is-ascii><h3><code><h- data-h=id>is_ascii</h-></code></h3></a>
<div class=toc-num data-level=3>3.3</div>
<a href=#base-parameter><h3><code><h- data-h=id>base</h-></code> parameter in <code><h- data-h=id>is_ascii_digit</h-></code></h3></a>
<div class=toc-num data-level=3>3.4</div>
<a href=#binary-and-octal-is-digit><h3><code><h- data-h=id>is_ascii_bit</h-></code> and <code><h- data-h=id>is_ascii_octal_digit</h-></code></h3></a>
<div class=toc-num data-level=3>3.5</div>
<a href=#case-insensitive-comparison><h3>Case-insensitive comparison functions</h3></a>
<div class=toc-num data-level=3>3.6</div>
<a href=#why-no-function-objects><h3>Why no function objects?</h3></a>
<div class=toc-num data-level=3>3.7</div>
<a href=#encoding><h3>What to do for ASCII-incompatible <code><h- data-h=kw_type>char</h-></code> and <code><h- data-h=kw_type>wchar_t</h-></code></h3></a>
<div class=toc-num data-level=4>3.7.1</div>
<a href=#conditionally-supported-char-overloads><h4>Conditionally supported <code><h- data-h=kw_type>char</h-></code> overloads</h4></a>
<div class=toc-num data-level=4>3.7.2</div>
<a href=#transcode-char-to-ascii><h4>Transcode <code><h- data-h=kw_type>char</h-></code> to ASCII</h4></a>
<div class=toc-num data-level=4>3.7.3</div>
<a href=#treat-the-input-as-ascii-regardless-of-the-literal-encoding><h4>Treat the input as ASCII, regardless of the literal encoding</h4></a>
<div class=toc-num data-level=3>3.8</div>
<a href=#what-if-the-input-is-a-non-ascii-code-unit><h3>What if the input is a non-ASCII code unit?</h3></a>
<div class=toc-num data-level=3>3.9</div>
<a href=#why-not-integers><h3>Why not accept any integer type?</h3></a>
<div class=toc-num data-level=3>3.10</div>
<a href=#ascii-case-insensitive-views-and-case-transformation-algorithms><h3>ASCII case-insensitive views and case transformation algorithms</h3></a>
<div class=toc-num data-level=3>3.11</div>
<a href=#why-just-ascii><h3>Why just ASCII?</h3></a>
<div class=toc-num data-level=2>4</div>
<a href=#implementation-experience><h2>Implementation experience</h2></a>
<div class=toc-num data-level=2>5</div>
<a href=#wording><h2>Wording</h2></a>
<div class=toc-num data-level=2>6</div>
<a href=#references><h2>References</h2></a>
</div>

<h2 id=revision-history><a class=para href=#revision-history></a>1. Revision history</h2>

<h3 id=changes-since-r1><a class=para href=#changes-since-r1></a>1.1. Changes since R1</h3>

<ul>
  <li>
    In <a href=#wording>§5. Wording</a>, fix incorrect return type
    for <code><h- data-h=id>ascii_case_insensitive_compare</h-></code> in synopsis
  </li>
  <li>
    In <a href=#wording>§5. Wording</a>, fix superfluous <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-></code> prefix
    for <code><h- data-h=id>strong_ordering</h-></code> in definition of <code><h- data-h=id>ascii_case_insensitive_compare</h-></code>
  </li>
</ul>

<h3 id=changes-since-r0><a class=para href=#changes-since-r0></a>1.2. Changes since R0</h3>

<ul>
  <li>In <a href=#base-parameter>§3.3. <code><h- data-h=id>base</h-></code> parameter in <code><h- data-h=id>is_ascii_digit</h-></code></a>, explain why the precondition is not hardened</li>
  <li>In <a href=#wording>§5. Wording</a>, fix a missing addition to <a href=https://eel.is/c++draft/tab:headers.cpp>[tab:headers.cpp]</a></li>
  <li>Minor editorial changes</li>
</ul>

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

<p>Testing whether a character falls into a specific subset of ASCII characters
or performing some simple transformations are common tasks in text processing.
For example, applications may need to check if identifiers
are comprised of alphanumeric ASCII characters or underscores;
Unicode properties are not relevant to this task,
and usually, neither are locales.
</p>
<p>Unfortunately, these common and simple tasks are only supported
through functions in the <code><h- data-h=str>&lt;cctype&gt;</h-></code> and <code><h- data-h=str>&lt;locale&gt;</h-></code> headers, such as:
</p><code-block><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> &lt;cctype&gt;</h->
<h- data-h=kw_type>int</h-> <h- data-h=id>isalnum</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>ch</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=kw_type>int</h-> <h- data-h=id>isalpha</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>ch</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> ...</h->
<h- data-h=kw_type>int</h-> <h- data-h=id>toupper</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>int</h-> <h- data-h=id>ch</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->

<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> &lt;locale&gt;</h->
<h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>charT</h-><h- data-h=sym_op>&gt;</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>isalnum</h-><h- data-h=sym_par>(</h-><h- data-h=id>charT</h-> <h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw>const</h-> <h- data-h=id>locale</h-><h- data-h=sym_op>&amp;</h-> <h- data-h=id>loc</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-> </code-block>

<p>Especially the <code><h- data-h=str>&lt;cctype&gt;</h-></code> functions are ridden with problems:
</p><ol>
  <li>
    There is no support for Unicode character types
    (<code><h- data-h=kw_type>char8_t</h-></code>, <code><h- data-h=kw_type>char16_t</h-></code>, and <code><h- data-h=kw_type>char32_t</h-></code>).
  </li>
  <li>
    These functions are not <code><h- data-h=kw>constexpr</h-></code>,
    but performing basic characters tests would be useful at compile time.
  </li>
  <li>
    There are distinct function names for <code><h- data-h=kw_type>char</h-></code> and <code><h- data-h=kw_type>wchar_t</h-></code>
    such as <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>isalnum</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>iswalnum</h-></code>,
    making generic programming more difficult.
  </li>
  <li>
    If <code><h- data-h=kw_type>char</h-></code> is signed,
    these functions can easily result in undefined behavior
    because the input must be representable as <code><h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>char</h-></code> or be <code><h- data-h=id>EOF</h-></code>.
    If <code><h- data-h=kw_type>char</h-></code> represents a UTF-8 code unit,
    passing any non-ASCII code unit into these functions has undefined behavior.
  </li>
  <li>
    These functions violate the zero-overhead principle
    by also handling an <code><h- data-h=id>EOF</h-></code> input,
    and in many use cases, <code><h- data-h=id>EOF</h-></code> will never be passed into these functions anyway.
    The caller can easily deal with <code><h- data-h=id>EOF</h-></code> themselves.
  </li>
  <li>
    The return type of charater tests is <code><h- data-h=kw_type>int</h-></code>,
    where a nonzero return value indicates that a test succeeded.
    This is very unnatural in C++, where <code><h- data-h=kw_type>bool</h-></code> is more idiomatic.
  </li>
  <li>
    Some functions use the currently installed <code><h- data-h=str_dlim>"</h-><h- data-h=str>C</h-><h- data-h=str_dlim>"</h-></code> locale,
    which makes their use questionable for high-performance tasks
    because each invocation is typically an opaque call that checks the current locale.
  </li>
</ol>

<p><strong>We propose lightweight replacement functions which address all these problems.</strong></p>

<note-block><p><intro-></intro-> 
Many of these problems are resolved by the
<code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>locale</h-></code> overloads in <code><h- data-h=str>&lt;locale&gt;</h-></code>,
but their locale dependence makes them unfit for what this proposal aims to achieve.
</p>
<p>Testing whether a <code><h- data-h=kw_type>char8_t</h-></code> (assumed to be a UTF-8 code unit)
is an ASCII digit is obviously a locale-independent task.
</p></note-block>

<h3 id=cant-you-implement-this-trivially-yourself><a class=para href=#cant-you-implement-this-trivially-yourself></a>2.1. Can't you implement this trivially yourself?</h3>

<p>It is worth noting that some of the functions can be implemented very easily by the user.
For example, existing code may already use a check like <code><h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>9</h-><h- data-h=str_dlim>'</h-></code>
to test for ASCII digits,
and our proposed <code><h- data-h=id>is_ascii_digit</h-></code> does just that.
</p>
<p>However, not all of the proposed functions are this simple.
For example, checking whether a <code><h- data-h=kw_type>char</h-></code> is an
ASCII punctuation character (<code><h- data-h=str_dlim>'</h-><h- data-h=str>#</h-><h- data-h=str_dlim>'</h-></code>, <code><h- data-h=str_dlim>'</h-><h- data-h=str>?</h-><h- data-h=str_dlim>'</h-></code>, etc.)
would require lots of separate checks done naively.
In the standard library, it can be efficiently implemented using a 128-bit or 256-bit bitset.
</p>
<p>Even if all proposed functions were trivial to implement,
working with ASCII characters is such an overwhelmingly common use case
that it's worth supporting in the standard library.
</p>
<h2 id=design><a class=para href=#design></a>3. Design</h2>

<p>All proposed functions are <code><h- data-h=kw>constexpr</h-></code>,
locale-independent,
overloaded (i.e. no separate name for separate input types),
and accept any character type
(<code><h- data-h=kw_type>char</h-></code>, <code><h- data-h=kw_type>wchar_t</h-></code>, <code><h- data-h=kw_type>char8_t</h-></code>, <code><h- data-h=kw_type>char16_t</h-></code>, and <code><h- data-h=kw_type>char32_t</h-></code>).
Furthermore, all function names contain <tt->ascii</tt->
to raise awareness for the fact that these functions do not handle Unicode characters.
A user would expect <code><h- data-h=id>is_upper</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>Ä</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> to be <code><h- data-h=bool>true</h-></code>,
but <code><h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>Ä</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> to be <code><h- data-h=bool>false</h-></code>.
</p>
<example-block><p><intro-></intro-> 
The counterpart to <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>isalpha</h-></code> is declared follows:
</p><code-block><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_alpha</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h-></code-block>
</example-block>

<p><code><i><h- data-h=id>character-type</h-></i></code> means that there exists an overload set where
this placeholder is replaced with each of the character types.
This design is more consistent with <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>from_chars</h-></code> and <code><h- data-h=str>&lt;cmath&gt;</h-></code> functions
than say, <code><h- data-h=kw>template</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw>class</h-> <h- data-h=id>Char</h-><h- data-h=sym_op>&gt;</h-></code>.
Equivalent functions could also be added to C, if there is interest.
This signature also allows the use with types that are convertible to a specific character type.
</p>
<h3 id=list-of-proposed-functions><a class=para href=#list-of-proposed-functions></a>3.1. List of proposed functions</h3>

<style>
#fun-table {
    margin-left: auto;
    margin-right: auto;
    max-width: 95%;
    table-layout: auto;
}
#fun-table td:not(:last-child),
#fun-table th {
    white-space: nowrap;
    vertical-align: top;
}
#fun-table td:last-child,
#fun-table th:last-child {
    width: 100%;
    text-align: center;
}
</style>

<p>Find below a list of proposed functions.
Note that the character set notation <tt->[</tt->...<tt->]</tt-> is taken from RegEx.
</p>
<table id=fun-table>
<tr>
  <th><code><h- data-h=str>&lt;cctype&gt;</h-></code></th>
  <th>Proposed name</th>
  <th>Returns (given ASCII <code><h- data-h=kw_type>char</h-> <h- data-h=id>c</h-></code>)</th>
</tr>
<tr>
  <td>N/A</td>
  <td><code><h- data-h=id>is_ascii</h-></code></td>
  <td><code><h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=num_deco>0x</h-><h- data-h=num>7F</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isdigit</h-></code></td>
  <td><code><h- data-h=id>is_ascii_digit</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[0-9]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td>N/A</td>
  <td><code><h- data-h=id>is_ascii_bit</h-></code></td>
  <td><code><h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>1</h-><h- data-h=str_dlim>'</h-></code></td>
</tr>
<tr>
  <td>N/A</td>
  <td><code><h- data-h=id>is_ascii_octal_digit</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[0-7]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isxdigit</h-></code></td>
  <td><code><h- data-h=id>is_ascii_hex_digit</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[0-9A-Fa-f]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>islower</h-></code></td>
  <td><code><h- data-h=id>is_ascii_lower</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[a-z]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isupper</h-></code></td>
  <td><code><h- data-h=id>is_ascii_upper</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[A-Z]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isalpha</h-></code></td>
  <td><code><h- data-h=id>is_ascii_alpha</h-></code></td>
  <td><code><h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isalnum</h-></code></td>
  <td><code><h- data-h=id>is_ascii_alphanumeric</h-></code></td>
  <td><code><h- data-h=id>is_ascii_alpha</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_asci_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>ispunct</h-></code></td>
  <td><code><h- data-h=id>is_ascii_punctuation</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[!"#$%&amp;'()*+,\-./:;&lt;=&gt;?@\[\\\]^_`{|}~]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isgraph</h-></code></td>
  <td><code><h- data-h=id>is_ascii_graphical</h-></code></td>
  <td><code><h- data-h=id>is_ascii_alphanumeric</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isprint</h-></code></td>
  <td><code><h- data-h=id>is_ascii_printable</h-></code></td>
  <td><code><h- data-h=id>is_ascii_graphical</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isblank</h-></code></td>
  <td><code><h- data-h=id>is_ascii_horizontal_whitespace</h-></code></td>
  <td><code><h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>t</h-><h- data-h=str_dlim>'</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>isspace</h-></code></td>
  <td><code><h- data-h=id>is_ascii_whitespace</h-></code></td>
  <td><code><h- data-h=bool>true</h-></code> if <code><h- data-h=id>c</h-></code> is in <tt-><h- data-h=str>[ \f\n\r\t\v]</h-></tt->, otherwise <code><h- data-h=bool>false</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>iscntrl</h-></code></td>
  <td><code><h- data-h=id>is_ascii_control</h-></code></td>
  <td><code><h- data-h=sym_par>(</h-><h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=num>0</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=num_deco>0x</h-><h- data-h=num>1F</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>N{DELETE}</h-><h- data-h=str_dlim>'</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>tolower</h-></code></td>
  <td><code><h- data-h=id>ascii_to_lower</h-></code></td>
  <td>the respective lower-case character if <code><h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code> is <code><h- data-h=bool>true</h-></code>, otherwise <code><h- data-h=id>c</h-></code></td>
</tr>
<tr>
  <td><code><h- data-h=id>toupper</h-></code></td>
  <td><code><h- data-h=id>ascii_to_upper</h-></code></td>
  <td>the respective upper-case character if <code><h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code> is <code><h- data-h=bool>true</h-></code>, otherwise <code><h- data-h=id>c</h-></code></td>
</tr>
<tr>
  <td>N/A</td>
  <td><code><h- data-h=id>ascii_case_insensitive_compare</h-></code></td>
  <td><i>see <a href=#case-insensitive-comparison>§3.5. Case-insensitive comparison functions</a></i></td>
</tr>
<tr>
  <td>N/A</td>
  <td><code><h- data-h=id>ascii_case_insensitive_equals</h-></code></td>
  <td><i>see <a href=#case-insensitive-comparison>§3.5. Case-insensitive comparison functions</a></i></td>
</tr>
</table>

<decision-block><p><intro-></intro-> 
The proposed names are mostly unabbreviated
to fit the rest of the standard library style.
Shorter names such as <code><h- data-h=id>is_ascii_alphanum</h-></code> or <code><h- data-h=id>is_ascii_alnum</h-></code>
could also be used.
</p></decision-block>

<decision-block><p><intro-></intro-> 
<code><h- data-h=id>isgraph</h-></code> should perhaps have no new version.
It is of questionable use,
and both the old and new name aren't obvious.
In the default <code><h- data-h=str_dlim>"</h-><h- data-h=str>C</h-><h- data-h=str_dlim>"</h-></code> locale,
<code><h- data-h=id>isgraph</h-></code> is simply <code><h- data-h=id>isprint</h-></code> without <code><h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-></code>.
</p>
<p>Similarly, <code><h- data-h=id>isblank</h-></code> should perhaps have no new version either.
This proposal simply has a new version for every <code><h- data-h=str>&lt;cctype&gt;</h-></code> function;
if need be, they are easy to remove.
</p></decision-block>

<h3 id=is-ascii><a class=para href=#is-ascii></a>3.2. <code><h- data-h=id>is_ascii</h-></code></h3>

<p>This additional function is mainly useful for checking if a character "is ASCII",
i.e. falls into the basic latin block,
before performing an ASCII-only evaluation.
</p>
<example-block><p><intro-></intro-> 
In the following overload set, the <code><h- data-h=kw_type>char32_t</h-></code> implementation delegates
to the <code><h- data-h=kw_type>char8_t</h-></code> implementation to avoid repetition of its logic.
The <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>is_ascii</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code> check is needed because
because an unconditional <code><h- data-h=id>get_hex_digit_value</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code>
may result in treating U+0130 LATIN CAPITAL LETTER I WITH DOT ABOVE as U+0030 DIGIT ZERO.
</p><code-block><h- data-h=kw_type>int</h-> <h- data-h=id>get_hex_digit_value</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>9</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>?</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h->
         <h- data-h=sym_punc>:</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>F</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>?</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h->
         <h- data-h=sym_punc>:</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>f</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>?</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h->
         <h- data-h=sym_punc>:</h-> <h- data-h=sym_op>-</h-><h- data-h=num>1</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h->

<h- data-h=kw_type>int</h-> <h- data-h=id>get_hex_digit_value</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char32_t</h-> <h- data-h=id>c</h-><h- data-h=sym_par>)</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>is_ascii</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>?</h-> <h- data-h=id>get_hex_digit_value</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=sym_op>-</h-><h- data-h=num>1</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>
</example-block>

<h3 id=base-parameter><a class=para href=#base-parameter></a>3.3. <code><h- data-h=id>base</h-></code> parameter in <code><h- data-h=id>is_ascii_digit</h-></code></h3>

<p>Similar to <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>to_chars</h-></code>,
<code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>is_ascii_digit</h-></code> can also take a <code><h- data-h=id>base</h-></code> parameter:
</p>
<code-block><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>base</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>10</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>If <code><h- data-h=id>base</h-></code> ≤ <code><h- data-h=num>10</h-></code>,
the range of valid ASCII digit character is simply limited.
For greater <code><h- data-h=id>base</h-></code>, a subset of alphabetic characters is also accepted,
starting with <code><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-></code> or <code><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-></code>.
Such a function is useful when parsing numbers with a base of choice,
which is what <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>to_chars</h-></code> does, for example.
</p>
<p>Similar to <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>from_chars</h-></code> and <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>to_chars</h-></code>,
the given <code><h- data-h=id>base</h-></code> has to be between 2 and 36 (inclusive).
This is a non-hardened precondition because all functions in <code><h- data-h=str>&lt;ascii&gt;</h-></code>
are low-level, high-performance, and spiritually numeric.
Hardened preconditions are not used within that context.
</p>
<h3 id=binary-and-octal-is-digit><a class=para href=#binary-and-octal-is-digit></a>3.4. <code><h- data-h=id>is_ascii_bit</h-></code> and <code><h- data-h=id>is_ascii_octal_digit</h-></code></h3>

<p>C++ and various other programming languages support binary and octal literals,
so it seems like an arbitrary choice to only have dedicated overloads for (hexa)decimal digits.
<code><h- data-h=id>is_ascii_bit</h-></code> may be especially useful,
such as when dealing with bit-strings like one of the <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>bitset</h-></code> constructors.
</p>
<p>In conclusion, we may as well have functions for bases 2, 8, 10, and 16;
they're not doing much harm, they're trivial to implement,
and some users may find them useful.
</p>
<note-block><p><intro-></intro-> 
None of the authors feel strongly about this,
so if LEWG insists,
we could remove <code><h- data-h=id>is_ascii_bit</h-></code> and <code><h- data-h=id>is_ascii_octal_digit</h-></code>,
and even remove <code><h- data-h=id>is_ascii_hex_digit</h-></code>,
leaving only the multi-base <code><h- data-h=id>is_ascii_digit</h-></code>.
</p></note-block>

<h3 id=case-insensitive-comparison><a class=para href=#case-insensitive-comparison></a>3.5. Case-insensitive comparison functions</h3>

<p>As shown in the table above,
we also propose the case-insensitive comparison functions.
</p>
<code-block><h- data-h=kw>constexpr</h-> <h- data-h=id>strong_ordering</h-> <h- data-h=id>ascii_case_insensitive_compare</h-><h- data-h=sym_par>(</h->
    <i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
    <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</h->
<h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=&gt;</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>b</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h->

<h- data-h=kw>constexpr</h-> <h- data-h=id>strong_ordering</h-> <h- data-h=id>ascii_case_insensitive_equals</h-><h- data-h=sym_par>(</h->
    <i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
    <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</h->
<h- data-h=sym_par>)</h-> <h- data-h=sym_brac>{</h->
    <h- data-h=kw_ctrl>return</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>b</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=sym_brac>}</h-></code-block>

<h3 id=why-no-function-objects><a class=para href=#why-no-function-objects></a>3.6. Why no function objects?</h3>

<p>For case-insensitive comparisons and for character tests in general,
function objects may be convenient because they can be more easily used in algorithms:
</p>
<code-block><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>string_view</h-> <h- data-h=id>str</h-> <h- data-h=sym_op>=</h-> <h- data-h=str_dlim>"</h-><h- data-h=str>abc123</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> This does not work if is_ascii_digit is an overloaded function or function template.</h->
<h- data-h=kw>auto</h-> <h- data-h=id>it</h-> <h- data-h=sym_op>=</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>find</h-><h- data-h=sym_par>(</h-><h- data-h=id>str</h-><h- data-h=sym_punc>,</h-> <h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>

<p>However, there is no reason why <code><h- data-h=id>is_ascii_digit</h-></code> <em>needs</em> to be a function object.
It is not a customization point, but a plain function.
Furthermore, defining function objects for this purpose may be obsoleted by
<a href="https://wg21%2elink/p3312r1">[P3312R1]</a> Overload Set Types.
</p>
<h3 id=encoding><a class=para href=#encoding></a>3.7. What to do for ASCII-incompatible <code><h- data-h=kw_type>char</h-></code> and <code><h- data-h=kw_type>wchar_t</h-></code></h3>

<p>Not every ordinary and wide character encoding is ASCII-compatible,
such as EBCDIC, Shift-JIS, and (defunct) ISO-646,
i.e. code units ≤ <code><h- data-h=num_deco>0x</h-><h- data-h=num>7f</h-></code> do not represent the same characters as ASCII.
</p>
<p>This begs the question:
what should <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> do on an EBCDIC platform,
where this call is <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char</h-><h- data-h=sym_par>(</h-><h- data-h=num_deco>0x</h-><h- data-h=num>f0</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code> ?
We have three options, discussed below.
</p>
<note-block><p><intro-></intro-> 
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>u8</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> is equivalent to <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-><h- data-h=sym_par>(</h-><h- data-h=num_deco>0x</h-><h- data-h=num>30</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code>
on any platform.
In general, the behavior for Unicode character types is obvious,
unlike that for <code><h- data-h=kw_type>char</h-></code> and <code><h- data-h=kw_type>wchar_t</h-></code>.
</p></note-block>

<h4 id=conditionally-supported-char-overloads><a class=para href=#conditionally-supported-char-overloads></a>3.7.1. Conditionally supported <code><h- data-h=kw_type>char</h-></code> overloads</h4>

<p>We could mandate that the ordinary literal encoding is an ASCII superset
for the <code><h- data-h=kw_type>char</h-></code> overload to exist.
This would force a cast (to <code><h- data-h=kw_type>char8_t</h-></code>) to use the functions on EBCDIC platforms.
It is not clear how implementations would treat Shift-JIS;
GCC assumes <code><h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>\</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>¥</h-><h- data-h=str_dlim>'</h-></code> to be <code><h- data-h=bool>true</h-></code>,
so this option may not be enough to alleviate
the awkwardness of <code><h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>¥</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code>.
</p>
<p>Also, this option is not very useful.
It is reasonable to have UTF-8 data stored in a <code><h- data-h=kw_type>char</h-><h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>]</h-></code> on EBCDIC platforms,
and having to perform casts to <code><h- data-h=kw_type>char8_t</h-></code> would be awkward.
</p>
<h4 id=transcode-char-to-ascii><a class=para href=#transcode-char-to-ascii></a>3.7.2. Transcode <code><h- data-h=kw_type>char</h-></code> to ASCII</h4>

<p>We could transcode from the ordinary literal encoding
to ASCII and produce an answer for the result of that transcoding.
This would be a greater burden for implementations,
especially on EBCDIC platforms.
The benefit is that <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> is always <code><h- data-h=bool>true</h-></code>,
although <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char</h-><h- data-h=sym_par>(</h-><h- data-h=num_deco>0x</h-><h- data-h=num>30</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code> may not be.
However, <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-><h- data-h=sym_par>(</h-><h- data-h=num_deco>0x</h-><h- data-h=num>30</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code> is always <code><h- data-h=bool>true</h-></code>.
</p>
<p>It probably does not solve the <code><h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>¥</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> case,
as implementers may keep transcoding <code><h- data-h=str_dlim>'</h-><h- data-h=str>¥</h-><h- data-h=str_dlim>'</h-></code> and <code><h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>\</h-><h- data-h=str_dlim>'</h-></code> in the same way.
It would also give incorrect answers for stateful encodings.
There are EBCDIC control characters that do not have an ASCII equivalent,
so if we were to do conversions, we would have to decide what,
for example, <code><h- data-h=id>is_ascii_control</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>u008B</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> should produce.
</p>
<note-block><p><intro-></intro-> 
This option was originally preferred by one of the authors,
but proved to be <em>hugely</em> unpopular in discussion of the proposal.
</p></note-block>

<h4 id=treat-the-input-as-ascii-regardless-of-the-literal-encoding><a class=para href=#treat-the-input-as-ascii-regardless-of-the-literal-encoding></a>3.7.3. Treat the input as ASCII, regardless of the literal encoding</h4>

<p><b>This is our proposed behavior.</b></p>

<p>The most simple option is to ignore literal encoding entirely,
and assume that <code><h- data-h=kw_type>char</h-></code> inputs are ASCII-encoded.
The greatest downside is that depending on encoding,
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> may be <code><h- data-h=bool>false</h-></code>,
which may be surprising to the user.
However, the main purpose of these functions is to be called with characters taken from ASCII text,
so what results they yield when passing literals is not so important.
</p>
<p>There are use cases for this behavior on EBCDIC platforms.
A lot of protocols (HTTP, POP) and file formats (JSON, XML) are ASCII/UTF-8-based
and need to be supported on EBCDIC systems,
making these functions universally useful,
especially as <code><h- data-h=str>&lt;cctype&gt;</h-></code> functions cannot easily be used to deal with ASCII on these platforms.
</p>
<p>Ultimately, do we want functions to deal with ASCII or the literal encoding?
If we want them to be a general way to query the ordinary literal encoding,
<code><h- data-h=id>is_ascii</h-></code> is a terrible name,
and finding a more general name would prove difficult.
</p>
<note-block><p><intro-></intro-> 
If we choose this option,
we can still provide the same transcoding functionality as the previous option
by offering a (literal-encoded) <code><h- data-h=kw_type>char</h-></code> → (code point) <code><h- data-h=kw_type>char32_t</h-></code> function,
although that may be outside the scope of this proposal.
</p></note-block>

<h3 id=what-if-the-input-is-a-non-ascii-code-unit><a class=para href=#what-if-the-input-is-a-non-ascii-code-unit></a>3.8. What if the input is a non-ASCII code unit?</h3>

<p>Text input is rarely guaranteed to be pure ASCII,
i.e. some code units may be &gt; <code><h- data-h=num_deco>0x</h-><h- data-h=num>7f</h-></code>.
However, we're still interested in ASCII characters within that input.
For example, we may
</p><ul>
<li>parse pure ASCII numbers like <code><h- data-h=num>123</h-></code> in a UTF-8 JSON (or other config) file,</li>
<li>trim ASCII whitespace in HTTP headers, which are encoded with ISO-8859-1,</li>
<li>
    parse ASCII-alphanumeric variable names in Lua scripts,
    where non-ASCII characters can appear (comments, string),
</li>
<li>...</li>
</ul>

<p>It is possible (and expected) that the user calls say,
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>ö</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code>, at least indirectly.
For the sake of convenience, all proposed functions should handle such inputs by
</p><ul>
    <li>returning <code><h- data-h=bool>false</h-></code> in the case of all testing functions, and</li>
    <li>applying an identity transformation in transformation/case-insensitive comparison functions.</li>
</ul>

<example-block><p><intro-></intro-> 
With these semantics, the user can safely write:
</p><code-block><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>u8string_view</h-> <h- data-h=id>str</h-> <h- data-h=sym_op>=</h-> <h- data-h=str_deco>u8</h-><h- data-h=str_dlim>"</h-><h- data-h=str>öab 123</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> it is an iterator to '1' because 'ö' is skipped</h->
<h- data-h=kw>auto</h-> <h- data-h=id>it</h-> <h- data-h=sym_op>=</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>find</h-><h- data-h=sym_par>(</h-><h- data-h=id>str</h-><h- data-h=sym_punc>,</h-> <h- data-h=sym_sqr>[</h-><h- data-h=sym_sqr>]</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char8_t</h-> <h- data-h=id>c</h-><h- data-h=sym_par>)</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>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-> <h- data-h=sym_brac>}</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>
<p>If <code><h- data-h=id>is_ascii_digit</h-></code> doesn't simply return <code><h- data-h=bool>false</h-></code> on non-ASCII inputs,
the proposal is useless for the common use case where some non-ASCII characters exist in the input.
</p></example-block>

<p>The proposed behavior also works excellently with any ASCII-compatible encoding, such as UTF-8.
Surrogate code units in UTF-8 are all greater than <code><h- data-h=num_deco>0x</h-><h- data-h=num>7F</h-></code>,
so if we implement say, <code><h- data-h=id>is_ascii_digit</h-></code> naively by checking
<code><h- data-h=id>c</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=id>c</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>9</h-><h- data-h=str_dlim>'</h-></code>, it "just works".
</p>
<h3 id=why-not-integers><a class=para href=#why-not-integers></a>3.9. Why not accept any integer type?</h3>

<p>Some people argue that a test like <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code>
is a purely numerical test using the ASCII table,
and so passing <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=num_deco>0x</h-><h- data-h=num>30</h-><h- data-h=sym_par>)</h-></code> should also be valid.
</p>
<p>However, this permissive interface would invite bugs.
For example, <code><h- data-h=id>c</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-></code> is the difference between ASCII characters, not an ASCII character,
so passing it into <code><h- data-h=id>is_ascii_digit</h-></code> would be nonsensical.
Static type systems exist for a reason:
to protect us from stupid mistakes.
While <code><h- data-h=kw_type>char</h-></code>, <code><h- data-h=kw_type>char32_t</h-></code> etc. are not required to be ASCII-encoded,
they are at least characters,
so passing them into our functions is likely something the user intended to do,
which we cannot say with confidence about <code><h- data-h=kw_type>int</h-></code>, <code><h- data-h=kw_type>unsigned</h-> <h- data-h=kw_type>int</h-></code>, etc.
</p>
<p>Additionally, if we allowed passing signed integers,
we may want to make the behavior erroneous or undefined for negative inputs
because <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=sym_op>-</h-><h- data-h=num>1</h-><h- data-h=num_dlim>'</h-><h- data-h=num>000</h-><h- data-h=num_dlim>'</h-><h- data-h=num>000</h-><h- data-h=sym_par>)</h-></code> is most likely a developer mistake.
Our interface is very simple:
it has a wide contract and almost all functions are <code><h- data-h=kw>noexcept</h-></code>.
Let's keep it that way!
</p>
<p>Lastly, even proponents of passing integer types would not want
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=bool>true</h-><h- data-h=sym_par>)</h-></code> to be valid.
</p>
<h3 id=ascii-case-insensitive-views-and-case-transformation-algorithms><a class=para href=#ascii-case-insensitive-views-and-case-transformation-algorithms></a>3.10. ASCII case-insensitive views and case transformation algorithms</h3>

<p>Ignoring or transforming ASCII case in algorithms is a fairly common problem.
Therefore, it may be useful to provide views such as <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>views</h-><h- data-h=sym_op>::</h-><h- data-h=id>ascii_lower</h-></code>,
algorithms like <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>equal_ascii_case_insensitive</h-></code>, etc.
</p>
<example-block><p><intro-></intro-> 
HTML tag names are case-insensitive and comprised of ASCII characters,
like <code><h- data-h=sym_punc>&lt;</h-><h- data-h=mk_tag>div</h-><h- data-h=sym_punc>&gt;</h-></code>, <code><h- data-h=sym_punc>&lt;</h-><h- data-h=mk_tag>DIV</h-><h- data-h=sym_punc>&gt;</h-></code> etc.
To identify a <code><h- data-h=sym_punc>&lt;</h-><h- data-h=mk_tag>div</h-><h- data-h=sym_punc>&gt;</h-></code> element, it would be nice if the user could write:
</p><code-block><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>equal</h-><h- data-h=sym_par>(</h-><h- data-h=id>tag_name</h-> <h- data-h=sym_op>|</h-> <h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>views</h-><h- data-h=sym_op>::</h-><h- data-h=id>ascii_lower</h-><h- data-h=sym_punc>,</h-> <h- data-h=str_dlim>"</h-><h- data-h=str>div</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> or</h->
<h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>ranges</h-><h- data-h=sym_op>::</h-><h- data-h=id>ascii_case_insensitive_equal</h-><h- data-h=sym_par>(</h-><h- data-h=id>tag_name</h-><h- data-h=sym_punc>,</h-> <h- data-h=str_dlim>"</h-><h- data-h=str>div</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
<h- data-h=cmt_dlim>//</h-><h- data-h=cmt> or</h->
<h- data-h=id>tag_name</h-><h- data-h=sym_op>.</h-><h- data-h=id>ascii_case_insensitive_equals</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>"</h-><h- data-h=str>div</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>
</example-block>

<p>While case transformations can be implemented naively using <code><h- data-h=id>std</h-><h- data-h=sym_op>::</h-><h- data-h=id>transform</h-></code>,
dedicated functions would allow an efficient vectorized implementation for contiguous ranges,
which can be many times faster (<a href="https://lemire%2eme/blog/2020/07/21/avoid-character-by-character-processing-when-performance-matters/">[AvoidCharByChar]</a>, <a href="https://lemire%2eme/blog/2024/08/03/converting-ascii-strings-to-lower-case-at-crazy-speeds-with-avx-512/">[AVX-512CaseConv]</a>)
Similarly, a case-insensitive comparison function can be vectorized.
In fact, POSIX's <code><h- data-h=id>strncasecmp</h-></code> has been heavily optimized in glibc (<a href="https://sourceware%2eorg/pipermail/libc-alpha/2022-March/137272%2ehtml">[AVX2strncasecmp]</a>),
and providing range-based interfaces would allow delegating to these heavily optimized functions.
</p>
<p><b>We intend to propose such utilities in a future paper or revision of this paper.</b>
Currently, this proposal is focused exclusively on operations involving character types.
</p>
<h3 id=why-just-ascii><a class=para href=#why-just-ascii></a>3.11. Why just ASCII?</h3>

<p>It may be tempting to generalize the proposed utilities beyond ASCII, e.g. to UTF-8.
However, this is not proposed for multiple reasons:
</p><ul>
<li>
    You cannot pass <code><h- data-h=kw_type>char8_t</h-></code> into a UTF-8 <code><h- data-h=id>is_upper</h-></code> function
    and expect meaningful results.
    In general, operations on variable-length encodings require sequences of code units.
    The interface we propose <em>only</em> makes sense for ASCII.
</li>
<li>
    Unicode utilities are tremendously more complex than ASCII utilities.
    Some Unicode case conversions even require multi-code-point changes.
</li>
</ul>


<h2 id=implementation-experience><a class=para href=#implementation-experience></a>4. Implementation experience</h2>

<p>A naive implementation of all proposed functions can be found at <a href="https://godbolt%2eorg/z/5nvWzdf8G">[CompilerExplorer]</a>,
although these are implemented as function templates,
not as overload sets (as proposed).
</p>
<p>A more advanced implementation of some functions can be found in <a href="https://github%2ecom/Eisenwave/ulight/blob/main/include/ulight/impl/ascii_chars%2ehpp">[µlight]</a>.
Character tests can be optimized using 128-bit or 256-bit bitsets.
</p>

<h2 id=wording><a class=para href=#wording></a>5. Wording</h2>

<p>The wording changes are relative to <a href="https://wg21%2elink/n5008">[N5008]</a>.
</p>
<p>In <a href=https://eel.is/c++draft/tab:headers.cpp>[tab:headers.cpp]</a>, add a new element to C++ library headers table:
</p>
<ins-block>
<p><tt->&lt;ascii&gt;</tt->
</p></ins-block>

<p>In subclause <a href=https://eel.is/c++draft/version.syn>[version.syn]</a>,
update the synopsis as follows:
</p>
<diff-block><code-block class=borderless><f-serif>[...]</f-serif>
<h- data-h=mac>#define __cpp_lib_as_const                          201510L </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> freestanding, also in &lt;utility&gt;</h->
<ins><h- data-h=mac>#define __cpp_lib_ascii                             20XXXXL </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> freestanding, also in &lt;ascii&gt;</h-></ins>
<h- data-h=mac>#define __cpp_lib_associative_heterogeneous_erasure 202110L </h-><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> also in </h-><f-serif><h- data-h=cmt>[...]</h-></f-serif>
<f-serif>[...]</f-serif></code-block></diff-block>

<p>In Clause <a href=https://eel.is/c++draft/text>[text]</a>,
append a new subclause:
</p>
<style>
ins-block .para::before {
    display: none;
}

.stable-ref {
    float: right;
}
</style>

<ins-block>
<h2 id=ascii-utilities-ascii><a class=para href=#ascii-utilities-ascii></a>ASCII utilities <span class=stable-ref>[ascii]</span></h2>

<p>Subclause [ascii] describes components for dealing with characters that are encoded using ASCII
or encodings that are ASCII-compatible, such as UTF-8.
</p>
<p><i>Recommended practice</i>:
Implementations should emit a warning when a function in this subclause is invoked
using a value produced by a <g-term>string-literal</g-term>
or <g-term>character-literal</g-term> whose encoding is ASCII-incompatible.<br/>
<wg21-block>[<i>Example</i>: 
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-></code> is <code><h- data-h=bool>false</h-></code> if the
ordinary literal encoding (<a href=https://eel.is/c++draft/lex.charset>[lex.charset]</a>) is EBCDIC
or some other ASCII-incompatible encoding,
which can be surprising to the user.
However, <code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=kw_type>char</h-><h- data-h=sym_brac>{</h-><h- data-h=num_deco>0x</h-><h- data-h=num>30</h-><h- data-h=sym_brac>}</h-><h- data-h=sym_par>)</h-></code>
is <code><h- data-h=bool>true</h-></code> regardless of ordinary literal encoding.
 — <i>end example</i>]</wg21-block></p>

<h3 id=header-ascii-synopsis-ascii.syn><a class=para href=#header-ascii-synopsis-ascii%2esyn></a>Header <tt->&lt;ascii&gt;</tt-> synopsis <span class=stable-ref>[ascii.syn]</span></h3>

<p>When a function is specified with a type placeholder of
<code><i><h- data-h=id>character-type</h-></i></code>,
the implementation provides overloads for all character types (<a href=https://eel.is/c++draft/basic.fundamental>[basic.fundamental]</a>)
in lieu of <code><i><h- data-h=id>character-type</h-></i></code>.
</p>
<code-block class=borderless><h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>all freestanding</h-></f-serif>
<h- data-h=kw>namespace</h-> <h- data-h=id>std</h-> <h- data-h=sym_brac>{</h->
  <h- data-h=cmt_dlim>//</h-><h- data-h=cmt> </h-><f-serif><h- data-h=cmt>[ascii.chars.test], ASCII character testing</h-></f-serif>
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>base</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>10</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_bit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_octal_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_hex_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_alpha</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_alphanumeric</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_graphical</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_printable</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_horizontal_whitespace</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_whitespace</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->

  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_control</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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> </h-><f-serif><h- data-h=cmt>[ascii.chars.transform], ASCII character transformation</h-></f-serif>
  <h- data-h=kw>constexpr</h-> <i><h- data-h=id>character-type</h-></i> <h- data-h=id>ascii_to_lower</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <i><h- data-h=id>character-type</h-></i> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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> </h-><f-serif><h- data-h=cmt>[ascii.chars.case.compare], ASCII case-insensitive character comparison</h-></f-serif>
  <h- data-h=kw>constexpr</h-> <h- data-h=id>strong_ordering</h-> <h- data-h=id>ascii_case_insensitive_compare</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h->
                                                           <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</h-><h- data-h=sym_par>)</h-> <h- data-h=kw>noexcept</h-><h- data-h=sym_punc>;</h->
  <h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>ascii_case_insensitive_equals</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h->
                                               <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</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>

<h3 id=ascii-character-testing-ascii.chars.test><a class=para href=#ascii-character-testing-ascii%2echars%2etest></a>ASCII character testing <span class=stable-ref>[ascii.chars.test]</span></h3>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=num_deco>0x</h-><h- data-h=num>7F</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=kw_type>int</h-> <h- data-h=id>base</h-> <h- data-h=sym_op>=</h-> <h- data-h=num>10</h-><h- data-h=sym_par>)</h-><h- data-h=sym_punc>;</h-></code-block>
<div class=indent>
<p><i>Preconditions</i>:
<code><h- data-h=id>base</h-></code> has a value between 2 and 36 (inclusive).
</p>
<p>
<i>Returns</i>:
<code-block class=borderless>   <h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>0</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>+</h-> <h- data-h=id>min</h-><h- data-h=sym_par>(</h-><h- data-h=id>base</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>10</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h->
<h- data-h=sym_op>||</h-> <h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>+</h-> <h- data-h=id>max</h-><h- data-h=sym_par>(</h-><h- data-h=id>base</h-> <h- data-h=sym_op>-</h-> <h- data-h=num>10</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>0</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h->
<h- data-h=sym_op>||</h-> <h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>+</h-> <h- data-h=id>max</h-><h- data-h=sym_par>(</h-><h- data-h=id>base</h-> <h- data-h=sym_op>-</h-> <h- data-h=num>10</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>0</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code-block>
</p>

<p><i>Remarks</i>:
A function call expression that violates the precondition
in the <i>Preconditions</i>: element
is not a core constant expression.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_bit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>2</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_octal_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>8</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_hex_digit</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_punc>,</h-> <h- data-h=num>16</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>z</h-><h- data-h=str_dlim>'</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&gt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>&amp;&amp;</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>Z</h-><h- data-h=str_dlim>'</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_alpha</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_alphanumeric</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_alpha</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_ascii_digit</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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 style=text-align:left>
<i>Returns</i>:
<code><h- data-h=id>u32string_view</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>U</h-><h- data-h=str_dlim>"</h-><h- data-h=str>!</h-><h- data-h=esc>\</h-><h- data-h=esc>"</h-><h- data-h=str>#</h-><h- data-h=str>$</h-><h- data-h=str>%</h-><h- data-h=str>&amp;'()*+,-./:;&lt;=&gt;?@[</h-><h- data-h=esc>\</h-><h- data-h=esc>\</h-><h- data-h=str>]^_`{|}~</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><wbr/><h- data-h=sym_op>.</h-><h- data-h=id>contains</h-><h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code>.
</p>
</div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_graphical</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_alphanumeric</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=id>is_ascii_punctuation</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_printable</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_graphical</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>||</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_horizontal_whitespace</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>||</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>t</h-><h- data-h=str_dlim>'</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_whitespace</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>u32string_view</h-><h- data-h=sym_par>(</h-><h- data-h=str_deco>U</h-><h- data-h=str_dlim>"</h-><h- data-h=str> </h-><h- data-h=esc>\</h-><h- data-h=esc>f</h-><h- data-h=esc>\</h-><h- data-h=esc>n</h-><h- data-h=esc>\</h-><h- data-h=esc>r</h-><h- data-h=esc>\</h-><h- data-h=esc>t</h-><h- data-h=esc>\</h-><h- data-h=esc>v</h-><h- data-h=str_dlim>"</h-><h- data-h=sym_par>)</h-><h- data-h=sym_op>.</h-><h- data-h=id>contains</h-><h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>is_ascii_control</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=</h-> <h- data-h=num_deco>0x</h-><h- data-h=num>1F</h-> <h- data-h=sym_op>||</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=esc>\</h-><h- data-h=esc>N{DELETE}</h-><h- data-h=str_dlim>'</h-></code>.
</p></div>

<h3 id=ascii-character-transformation-ascii.chars.transform><a class=para href=#ascii-character-transformation-ascii%2echars%2etransform></a>ASCII character transformation <span class=stable-ref>[ascii.chars.transform]</span></h3>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <i><h- data-h=id>character-type</h-></i> <h- data-h=id>ascii_to_lower</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>?</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>character-type</h-></i><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>+</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>c</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <i><h- data-h=id>character-type</h-></i> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>c</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>Returns</i>:
<code><h- data-h=id>is_ascii_lower</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>?</h-> <h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><i><h- data-h=id>character-type</h-></i><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>-</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>a</h-><h- data-h=str_dlim>'</h-> <h- data-h=sym_op>+</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str>A</h-><h- data-h=str_dlim>'</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_punc>:</h-> <h- data-h=id>c</h-></code>.
</p></div>

<h3 id=ascii-case-insensitive-character-comparison-ascii.chars.case.compare><a class=para href=#ascii-case-insensitive-character-comparison-ascii%2echars%2ecase%2ecompare></a>ASCII case-insensitive character comparison <span class=stable-ref>[ascii.chars.case.compare]</span></h3>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=id>strong_ordering</h-> <h- data-h=id>ascii_case_insensitive_compare</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
                                                         <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</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>Returns</i>:
<code><h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>&lt;=&gt;</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>b</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

<code-block class=borderless><h- data-h=kw>constexpr</h-> <h- data-h=kw_type>bool</h-> <h- data-h=id>ascii_case_insensitive_equals</h-><h- data-h=sym_par>(</h-><i><h- data-h=id>character-type</h-></i> <h- data-h=id>a</h-><h- data-h=sym_punc>,</h->
                                             <i><h- data-h=id>character-type</h-></i> <h- data-h=id>b</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>Returns</i>:
<code><h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>a</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=id>ascii_to_upper</h-><h- data-h=sym_par>(</h-><h- data-h=id>b</h-><h- data-h=sym_par>)</h-></code>.
</p></div>

</ins-block>

<hr/>

<note-block><p><intro-></intro-> 
Some uses of <code><h- data-h=kw>static_cast</h-></code> are unnecessary to describe semantics.
For example, <code><h- data-h=kw>static_cast</h-><h- data-h=sym_op>&lt;</h-><h- data-h=kw_type>char32_t</h-><h- data-h=sym_op>&gt;</h-><h- data-h=sym_par>(</h-><h- data-h=id>c</h-><h- data-h=sym_par>)</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-></code>
is equivalent to <code><h- data-h=id>c</h-> <h- data-h=sym_op>==</h-> <h- data-h=str_deco>U</h-><h- data-h=str_dlim>'</h-><h- data-h=str> </h-><h- data-h=str_dlim>'</h-></code>.
</p>
<p>However, these uses of <code><h- data-h=kw>static_cast</h-></code> may improve readability and avoid
the use of behavior which is proposed to be deprecated in <a href="https://wg21%2elink/p3695r0">[P3695R0]</a>.
</p></note-block>


<h2 id=references><a class=para href=#references></a>6. 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-P3312R1" class=bib-item>
<a href="https://wg21%2elink/p3312r1">[P3312R1]</a>
<span class=bib-author>Bengt Gustafsson.</span>
<span class=bib-title>Overload Set Types</span>
<span class=bib-date>2025-04-16</span>
<a href="https://www%2eopen-std%2eorg/jtc1/sc22/wg21/docs/papers/2025/p3312r1%2epdf" class=bib-link>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3312r1.pdf</a></div><div id="bib-item-P3695R0" class=bib-item>
<a href="https://wg21%2elink/p3695r0">[P3695R0]</a>
<span class=bib-author>Jan Schultke.</span>
<span class=bib-title>Deprecate implicit conversions between char8_t, char16_t, and char32_t</span>
<span class=bib-date>2025-05-18</span>
<a href="https://isocpp%2eorg/files/papers/P3695R0%2ehtml" class=bib-link>https://isocpp.org/files/papers/P3695R0.html</a></div><div id="bib-item-CompilerExplorer" class=bib-item>
<a href="https://godbolt%2eorg/z/5nvWzdf8G">[CompilerExplorer]</a>
<span class=bib-author>Jan Schultke, Corentin Jabot.</span>
<span class=bib-title>Partial implementation of character utilities</span>
<a href="https://godbolt%2eorg/z/5nvWzdf8G" class=bib-link>https://godbolt.org/z/5nvWzdf8G</a></div><div id="bib-item-µlight" class=bib-item>
<a href="https://github%2ecom/Eisenwave/ulight/blob/main/include/ulight/impl/ascii_chars%2ehpp">[µlight]</a>
<span class=bib-author>Jan Schultke.</span>
<span class=bib-title>ascii_chars.hpp utilities in µlight</span>
<a href="https://github%2ecom/Eisenwave/ulight/blob/main/include/ulight/impl/ascii_chars%2ehpp" class=bib-link>https://github.com/Eisenwave/ulight/blob/main/include/ulight/impl/ascii_chars.hpp</a></div><div id="bib-item-AVX2strncasecmp" class=bib-item>
<a href="https://sourceware%2eorg/pipermail/libc-alpha/2022-March/137272%2ehtml">[AVX2strncasecmp]</a>
<span class=bib-author>Noah Goldstein.</span>
<span class=bib-title>glibc [PATCH v1 21/23] x86: Add AVX2 optimized str{n}casecmp</span>
<span class=bib-date>2022-03-23</span>
<a href="https://sourceware%2eorg/pipermail/libc-alpha/2022-March/137272%2ehtml" class=bib-link>https://sourceware.org/pipermail/libc-alpha/2022-March/137272.html</a></div><div id="bib-item-AvoidCharByChar" class=bib-item>
<a href="https://lemire%2eme/blog/2020/07/21/avoid-character-by-character-processing-when-performance-matters/">[AvoidCharByChar]</a>
<span class=bib-author>Daniel Lemire.</span>
<span class=bib-title>Avoid character-by-character processing when performance matters</span>
<span class=bib-date>2020-07-21</span>
<a href="https://lemire%2eme/blog/2020/07/21/avoid-character-by-character-processing-when-performance-matters/" class=bib-link>https://lemire.me/blog/2020/07/21/avoid-character-by-character-processing-when-performance-matters/</a></div><div id="bib-item-AVX-512CaseConv" class=bib-item>
<a href="https://lemire%2eme/blog/2024/08/03/converting-ascii-strings-to-lower-case-at-crazy-speeds-with-avx-512/">[AVX-512CaseConv]</a>
<span class=bib-author>Daniel Lemire.</span>
<span class=bib-title>Converting ASCII strings to lower case at crazy speeds with AVX-512</span>
<span class=bib-date>2024-08-03</span>
<a href="https://lemire%2eme/blog/2024/08/03/converting-ascii-strings-to-lower-case-at-crazy-speeds-with-avx-512/" class=bib-link>https://lemire.me/blog/2024/08/03/converting-ascii-strings-to-lower-case-at-crazy-speeds-with-avx-512/</a></div></div>
</main></body>
</html>
