<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P3104R4: Bit permutations</title>
<style data-fill-with="stylesheet">/******************************************************************************
 *                   Style sheet for the W3C specifications                   *
 *
 * Special classes handled by this style sheet include:
 *
 * Indices
 *   - .toc for the Table of Contents (<ol class="toc">)
 *     + <span class="secno"> for the section numbers
 *   - #toc for the Table of Contents (<nav id="toc">)
 *   - ul.index for Indices (<a href="#ref">term</a><span>, in § N.M</span>)
 *   - table.index for Index Tables (e.g. for properties or elements)
 *
 * Structural Markup
 *   - table.data for general data tables
 *     -> use 'scope' attribute, <colgroup>, <thead>, and <tbody> for best results !
 *     -> use <table class='complex data'> for extra-complex tables
 *     -> use <td class='long'> for paragraph-length cell content
 *     -> use <td class='pre'> when manual line breaks/indentation would help readability
 *   - dl.switch for switch statements
 *   - ol.algorithm for algorithms (helps to visualize nesting)
 *   - .figure and .caption (HTML4) and figure and figcaption (HTML5)
 *     -> .sidefigure for right-floated figures
 *   - ins/del
 *     -> ins/del.c### for candidate and proposed changes (amendments)
 *
 * Code
 *   - pre and code
 *
 * Special Sections
 *   - .note       for informative notes             (div, p, span, aside, details)
 *   - .example    for informative examples          (div, p, pre, span)
 *   - .issue      for issues                        (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *   - .correction for "candidate corrections"       (div, aside, details, section)
 *   - .addition   for "candidate additions"         (div, aside, details, section)
 *   - .correction.proposed for "proposed corrections" (div, aside, details, section)
 *   - .addition.proposed   for "proposed additions"   (div, aside, details, section)
 *
 * Definition Boxes
 *   - pre.def   for WebIDL definitions
 *   - table.def for tables that define other entities (e.g. CSS properties)
 *   - dl.def    for definition lists that define other entitles (e.g. HTML elements)
 *
 * Numbering
 *   - .secno for section numbers in .toc and headings (<span class='secno'>3.2</span>)
 *   - .marker for source-inserted example/figure/issue numbers (<span class='marker'>Issue 4</span>)
 *   - ::before styled for CSS-generated issue/example/figure numbers:
 *     -> Documents wishing to use this only need to add
 *        figcaption::before,
 *        .caption::before { content: "Figure "  counter(figure) " ";  }
 *        .example::before { content: "Example " counter(example) " "; }
 *        .issue::before   { content: "Issue "   counter(issue) " ";   }
 *
 * Header Stuff (ignore, just don't conflict with these classes)
 *   - .head for the header
 *   - .copyright for the copyright
 *
 * Outdated warning for old specs
 *
 * Miscellaneous
 *   - .overlarge for things that should be as wide as possible, even if
 *     that overflows the body text area. This can be used on an item or
 *     on its container, depending on the effect desired.
 *     Note that this styling basically doesn't help at all when printing,
 *     since A4 paper isn't much wider than the max-width here.
 *     It's better to design things to fit into a narrower measure if possible.
 *
 *   - js-added ToC jump links (see fixup.js)
 *
 ******************************************************************************/

/* color variables included separately for reliability */

/******************************************************************************/
/*                                    Body                                    */
/******************************************************************************/

	html {
	}

	body {
		counter-reset: example figure issue;

		/* Layout */
		max-width: 50em;			  /* limit line length to 50em for readability   */
		margin: 0 auto;				/* center text within page                    */
		padding: 1.6em 1.5em 2em 50px; /* assume 16px font size for downlevel clients */
		padding: 1.6em 1.5em 2em calc(26px + 1.5em); /* leave space for status flag    */

		/* Typography */
		line-height: 1.5;
		font-family: sans-serif;
		widows: 2;
		orphans: 2;
		word-wrap: break-word;
		overflow-wrap: break-word;
		hyphens: auto;

		color: black;
		color: var(--text);
		background: white top left fixed no-repeat;
		background: var(--bg) top left fixed no-repeat;
		background-size: 25px auto;
	}


/******************************************************************************/
/*                         Front Matter & Navigation                          */
/******************************************************************************/

/** Header ********************************************************************/

	div.head { margin-bottom: 1em; }
	div.head hr { border-style: solid; }

	div.head h1 {
		font-weight: bold;
		margin: 0 0 .1em;
		font-size: 220%;
	}

	div.head h2 { margin-bottom: 1.5em;}

/** W3C Logo ******************************************************************/

	.head .logo {
		float: right;
		margin: 0.4rem 0 0.2rem .4rem;
	}

	.head img[src*="logos/W3C"] {
		display: block;
		border: solid #1a5e9a;
		border: solid var(--logo-bg);
		border-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		background: var(--logo-bg);
		color: white;
		color: var(--logo-text);
		font-weight: bold;
	}

	.head a:hover > img[src*="logos/W3C"],
	.head a:focus > img[src*="logos/W3C"] {
		opacity: .8;
	}

	.head a:active > img[src*="logos/W3C"] {
		background: #c00;
		background: var(--logo-active-bg);
		border-color: #c00;
		border-color: var(--logo-active-bg);
	}

	/* see also additional rules in Link Styling section */

/** Copyright *****************************************************************/

	p.copyright,
	p.copyright small { font-size: small; }

/** Back to Top / ToC Toggle **************************************************/

	@media print {
		#toc-nav {
			display: none;
		}
	}
	@media not print {
		#toc-nav {
			position: fixed;
			z-index: 3;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

			height: 1.33em;
			padding: .1em 0.3em;
			margin: 0;

			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;

			color: #707070;
			color: var(--tocnav-normal-text);
			background: white;
			background: var(--tocnav-normal-bg);
		}
		#toc-nav > a:hover,
		#toc-nav > a:focus {
			color: black;
			color: var(--tocnav-hover-text);
			background: #f8f8f8;
			background: var(--tocnav-hover-bg);
		}
		#toc-nav > a:active {
			color: #c00;
			color: var(--tocnav-active-text);
			background: white;
			background: var(--tocnav-active-bg);
		}

		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		/* statusbar gets in the way on keyboard focus; remove once browsers fix */
		#toc-nav > a[href="#toc"]:not(:hover):focus:last-child {
			padding-bottom: 1.5rem;
		}

		#toc-nav:not(:hover) > a:not(:focus) > span + span {
			/* Ideally this uses :focus-within on #toc-nav */
			display: none;
		}
		#toc-nav > a > span + span {
			padding-right: 0.2em;
		}
	}

/** ToC Sidebar ***************************************************************/

	/* Floating sidebar */
	@media screen {
		body.toc-sidebar #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			max-width: 80%;
			max-width: calc(100% - 2em - 26px);
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body.toc-sidebar #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}
		body.toc-sidebar #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	/* Hide main scroller when only the ToC is visible anyway */
	@media screen and (max-width: 28em) {
		body.toc-sidebar {
			overflow: hidden;
		}
	}

	/* Sidebar with its own space */
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) #toc {
			position: fixed;
			top: 0; bottom: 0;
			left: 0;
			width: 23.5em;
			overflow: auto;
			padding: 0 1em;
			padding-left: 42px;
			padding-left: calc(1em + 26px);
			color: black;
			color: var(--tocsidebar-text);
			background: inherit;
			background-color: #f7f8f9;
			background-color: var(--tocsidebar-bg);
			z-index: 1;
			box-shadow: -.1em 0 .25em rgba(0,0,0,.1) inset;
			box-shadow: -.1em 0 .25em var(--tocsidebar-shadow) inset;
		}
		body:not(.toc-inline) #toc h2 {
			margin-top: .8rem;
			font-variant: small-caps;
			font-variant: all-small-caps;
			text-transform: lowercase;
			font-weight: bold;
			color: gray;
			color: hsla(203,20%,40%,.7);
			color: var(--tocsidebar-heading-text);
		}

		body:not(.toc-inline) {
			padding-left: 29em;
		}
		/* See also Overflow section at the bottom */

		body:not(.toc-inline) #toc-jump:not(:focus) {
			width: 0;
			height: 0;
			padding: 0;
			position: absolute;
			overflow: hidden;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) {
			margin: 0 4em;
		}
	}

/******************************************************************************/
/*                                Sectioning                                  */
/******************************************************************************/

/** Headings ******************************************************************/

	h1, h2, h3, h4, h5, h6, dt {
		page-break-after: avoid;
		page-break-inside: avoid;
		font: 100% sans-serif;   /* Reset all font styling to clear out UA styles */
		font-family: inherit;	/* Inherit the font family. */
		line-height: 1.2;		/* Keep wrapped headings compact */
		hyphens: manual;		/* Hyphenated headings look weird */
	}

	h2, h3, h4, h5, h6 {
		margin-top: 3rem;
	}

	h1, h2, h3 {
		color: #005A9C;
		color: var(--heading-text);
	}

	h1 { font-size: 170%; }
	h2 { font-size: 140%; }
	h3 { font-size: 120%; }
	h4 { font-weight: bold; }
	h5 { font-style: italic; }
	h6 { font-variant: small-caps; }
	dt { font-weight: bold; }

/** Subheadings ***************************************************************/

	h1 + h2,
	#profile-and-date {
		/* #profile-and-date is a subtitle in an H2 under the H1 */
		margin-top: 0;
	}
	h2 + h3,
	h3 + h4,
	h4 + h5,
	h5 + h6 {
		margin-top: 1.2em; /* = 1 x line-height */
	}

/** Section divider ***********************************************************/

	:not(.head) > :not(.head) + hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		color: black;
		color: var(--hr-text);
		border: transparent solid 0;
		background: transparent;
	}
	:not(.head) > hr::before {
		content: "\2727\2003\2003\2727\2003\2003\2727";
	}

/******************************************************************************/
/*                            Paragraphs and Lists                            */
/******************************************************************************/

	p {
		margin: 1em 0;
	}

	dd > p:first-child,
	li > p:first-child {
		margin-top: 0;
	}

	ul, ol {
		margin-left: 0;
		padding-left: 2em;
	}

	li {
		margin: 0.25em 0 0.5em;
		padding: 0;
	}

	dl dd {
		margin: 0 0 .5em 2em;
	}

	.head dd + dd { /* compact for header */
		margin-top: -.5em;
	}

	/* Style for algorithms */
	ol.algorithm ol:not(.algorithm),
	.algorithm > ol ol:not(.algorithm) {
	border-left: 0.5em solid #DEF;
	border-left: 0.5em solid var(--algo-border);
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	 padding: .5em;
	 border: thin solid #ddd;
	 border: thin solid var(--algo-border);
	 border-radius: .5em;
	 margin: .5em calc(-0.5em - 1px);
	}
	[data-algorithm]:not(.heading) > :first-child {
	 margin-top: 0;
	}
	[data-algorithm]:not(.heading) > :last-child {
	 margin-bottom: 0;
	}

	/* Style for switch/case <dl>s */
	dl.switch > dd > ol.only,
	dl.switch > dd > .only > ol {
	margin-left: 0;
	}
	dl.switch > dd > ol.algorithm,
	dl.switch > dd > .algorithm > ol {
	margin-left: -2em;
	}
	dl.switch {
	padding-left: 2em;
	}
	dl.switch > dt {
	text-indent: -1.5em;
	margin-top: 1em;
	}
	dl.switch > dt + dt {
	margin-top: 0;
	}
	dl.switch > dt::before {
	content: '\21AA';
	padding: 0 0.5em 0 0;
	display: inline-block;
	width: 1em;
	text-align: right;
	line-height: 0.5em;
	}

/** Terminology Markup ********************************************************/


/******************************************************************************/
/*                                 Inline Markup                              */
/******************************************************************************/

/** Terminology Markup ********************************************************/
	dfn   { /* Defining instance */
		font-weight: bolder;
	}
	a > i { /* Instance of term */
		font-style: normal;
	}
	dt dfn code, code.idl {
		font-size: inherit;
	}
	dfn var {
		font-style: normal;
	}

/** Change Marking ************************************************************/

	del {
		color: #aa0000;
		color: var(--del-text);
		background: transparent;
		background: var(--del-bg);
		text-decoration: line-through;
	}
	ins {
		color: #006100;
		color: var(--ins-text);
		background: transparent;
		background: var(--ins-bg);
		text-decoration: underline;
	}

	/* for amendments (candidate/proposed changes) */

	.amendment ins, .correction ins, .addition ins,
	ins[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment del, .correction del, .addition del,
	del[class^=c] {
		text-decoration-style: dotted;
	}
	.amendment.proposed ins, .correction.proposed ins, .addition.proposed ins,
	ins[class^=c].proposed {
		text-decoration-style: double;
	}
	.amendment.proposed del, .correction.proposed del, .addition.proposed del,
	del[class^=c].proposed {
		text-decoration-style: double;
	}

/** Miscellaneous improvements to inline formatting ***************************/

	sup {
		vertical-align: super;
		font-size: 80%
	}

/******************************************************************************/
/*                                    Code                                    */
/******************************************************************************/

/** General monospace/pre rules ***********************************************/

	pre, code, samp {
		font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
		font-size: .9em;
		hyphens: none;
		text-transform: none;
		text-align: left;
		text-align: start;
		font-variant: normal;
		orphans: 3;
		widows: 3;
		page-break-before: avoid;
	}
	pre code,
	code code {
		font-size: 100%;
	}

	pre {
		margin-top: 1em;
		margin-bottom: 1em;
		overflow: auto;
	}

/** Inline Code fragments *****************************************************/

	/* Do something nice. */

/******************************************************************************/
/*                                    Links                                   */
/******************************************************************************/

/** General Hyperlinks ********************************************************/

	/* We hyperlink a lot, so make it less intrusive */
	a[href] {
		color: #034575;
		color: var(--a-normal-text);
		text-decoration: underline #707070;
		text-decoration: underline var(--a-normal-underline);
		text-decoration-skip-ink: none;
	}
	a:visited {
		color: #034575;
		color: var(--a-visited-text);
		text-decoration-color: #bbb;
		text-decoration-color: var(--a-visited-underline);
	}

	/* Indicate interaction with the link */
	a[href]:focus,
	a[href]:hover {
		text-decoration-thickness: 2px;
	}
	a[href]:active {
		color: #c00;
		color: var(--a-active-text);
		text-decoration-color: #c00;
		text-decoration-color: var(--a-active-underline);
	}

	/* Backout above styling for W3C logo */
	.head .logo,
	.head .logo a {
		border: none;
		text-decoration: none;
		background: transparent;
	}

/******************************************************************************/
/*                                    Images                                  */
/******************************************************************************/

	img {
		border-style: none;
	}

	img, svg {
		/* Intentionally not color-scheme aware. */
		background: white;
	}

	/* For autogen numbers, add
	  .caption::before, figcaption::before { content: "Figure " counter(figure) ". "; }
	*/

	figure, .figure, .sidefigure {
		page-break-inside: avoid;
		text-align: center;
		margin: 2.5em 0;
	}
	.figure img,	.sidefigure img,	figure img,
	.figure object, .sidefigure object, figure object {
		max-width: 100%;
		margin: auto;
		height: auto;
	}
	.figure pre, .sidefigure pre, figure pre {
		text-align: left;
		display: table;
		margin: 1em auto;
	}
	.figure table, figure table {
		margin: auto;
	}
	@media screen and (min-width: 20em) {
		.sidefigure {
			float: right;
			width: 50%;
			margin: 0 0 0.5em 0.5em;
		}
	}
	.caption, figcaption, caption {
		font-style: italic;
		font-size: 90%;
	}
	.caption::before, figcaption::before, figcaption > .marker {
		font-weight: bold;
	}
	.caption, figcaption {
		counter-increment: figure;
	}

	/* DL list is indented 2em, but figure inside it is not */
	dd > .figure, dd > figure { margin-left: -2em; }

/******************************************************************************/
/*                             Colored Boxes                                  */
/******************************************************************************/

	.issue, .note, .example, .assertion, .advisement, blockquote,
	.amendment, .correction, .addition {
		margin: 1em auto;
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	blockquote > :first-child,
	.note  > p:first-child,
	.issue > p:first-child,
	.amendment > p:first-child,
	.correction > p:first-child,
	.addition > p:first-child {
		margin-top: 0;
	}
	blockquote > :last-child,
	.note  > p:last-child,
	.issue > p:last-child,
	.amendment > p:last-child,
	.correction > p:last-child,
	.addition > p:last-child {
		margin-bottom: 0;
	}


	.issue::before, .issue > .marker,
	.example::before, .example > .marker,
	.note::before, .note > .marker,
	details.note > summary > .marker,
	.amendment::before, .amendment > .marker,
	details.amendment > summary > .marker,
	.addition::before, .addition > .marker,
	addition.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	correction.amendment > summary > .marker
	{
		text-transform: uppercase;
		padding-right: 1em;
	}

	.example::before, .example > .marker {
		display: block;
		padding-right: 0em;
	}

/** Blockquotes ***************************************************************/

	blockquote {
		border-color: silver;
		border-color: var(--blockquote-border);
		background: transparent;
		background: var(--blockquote-bg);
		color: currentcolor;
		color: var(--blockquote-text);
	}

/** Open issue ****************************************************************/

	.issue {
		border-color: #e05252;
		border-color: var(--issue-border);
		background: #fbe9e9;
		background: var(--issue-bg);
		color: black;
		color: var(--issue-text);
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		color: #831616;
		color: var(--issueheading-text);
	}
	/* Add .issue::before { content: "Issue " counter(issue) " "; } for autogen numbers,
	  or use class="marker" to mark up the issue number in source. */

/** Example *******************************************************************/

	.example {
		border-color: #e0cb52;
		border-color: var(--example-border);
		background: #fcfaee;
		background: var(--example-bg);
		color: black;
		color: var(--example-text);
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		color: #574b0f;
		color: var(--exampleheading-text);
	}
	/* Add .example::before { content: "Example " counter(example) " "; } for autogen numbers,
	  or use class="marker" to mark up the example number in source. */

/** Non-normative Note ********************************************************/

	.note {
		border-color: #52e052;
		border-color: var(--note-border);
		background: #e9fbe9;
		background: var(--note-bg);
		color: black;
		color: var(--note-text);
		overflow: auto;
	}

	.note::before, .note > .marker,
	details.note > summary {
		color: hsl(120, 70%, 30%);
		color: var(--noteheading-text);
	}
	/* Add .note::before { content: "Note "; } for autogen label,
	  or use class="marker" to mark up the label in source. */

	details.note[open] > summary {
		border-bottom: 1px silver solid;
		border-bottom: 1px var(--notesummary-underline) solid;
	}

/** Assertion Box *************************************************************/
	/*  for assertions in algorithms */

	.assertion {
		border-color: #AAA;
		border-color: var(--assertion-border);
		background: #EEE;
		background: var(--assertion-bg);
		color: black;
		color: var(--assertion-text);
	}

/** Advisement Box ************************************************************/
	/*  for attention-grabbing normative statements */

	.advisement {
		border-color: orange;
		border-color: var(--advisement-border);
		border-style: none solid;
		background: #fec;
		background: var(--advisement-bg);
		color: black;
		color: var(--advisement-text);
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement::before, .advisement > .marker {
		color: #b35f00;
		color: var(--advisementheading-text);
	}

/** Amendment Box *************************************************************/

	.amendment, .correction, .addition {
		border-color: #330099;
		border-color: var(--amendment-border);
		background: #F5F0FF;
		background: var(--amendment-bg);
		color: black;
		color: var(--amendment-text);
	}
	.amendment.proposed, .correction.proposed, .addition.proposed {
		border-style: solid;
		border-block-width: 0.25em;
	}
	.amendment::before, .amendment > .marker,
	details.amendment > summary::before, details.amendment > summary > .marker,
	.correction::before, .correction > .marker,
	details.correction > summary::before, details.correction > summary > .marker,
	.addition::before, .addition > .marker,
	details.addition > summary::before, details.addition > summary > .marker {
		color: #220066;
		color: var(--amendmentheading-text);
	}
	.amendment.proposed::before, .amendment.proposed > .marker,
	details.amendment.proposed > summary::before, details.amendment.proposed > summary > .marker,
	.correction.proposed::before, .correction.proposed > .marker,
	details.correction.proposed > summary::before, details.correction.proposed > summary > .marker,
	.addition.proposed::before, .addition.proposed > .marker,
	details.addition.proposed > summary::before, details.addition.proposed > summary > .marker {
		font-weight: bold;
	}

/** Spec Obsoletion Notice ****************************************************/
	/* obnoxious obsoletion notice for older/abandoned specs. */

	details {
		display: block;
	}
	summary {
		font-weight: bolder;
	}

	.annoying-warning:not(details),
	details.annoying-warning:not([open]) > summary,
	details.annoying-warning[open] {
		background: hsla(40,100%,50%,0.95);
		background: var(--warning-bg);
		color: black;
		color: var(--warning-text);
		padding: .75em 1em;
		border: red;
		border: var(--warning-border);
		border-style: solid none;
		box-shadow: 0 2px 8px black;
		text-align: center;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

@media not print {
	details.annoying-warning[open] {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 2em;
		z-index: 1000;
	}
}

	details.annoying-warning:not([open]) > summary {
		text-align: center;
	}

/** Entity Definition Boxes ***************************************************/

	.def {
		padding: .5em 1em;
		background: #def;
		background: var(--def-bg);
		margin: 1.2em 0;
		border-left: 0.5em solid #8ccbf2;
		border-left: 0.5em solid var(--def-border);
		color: black;
		color: var(--def-text);
	}

/******************************************************************************/
/*                                    Tables                                  */
/******************************************************************************/

	th, td {
		text-align: left;
		text-align: start;
	}

/** Property/Descriptor Definition Tables *************************************/

	table.def {
		/* inherits .def box styling, see above */
		width: 100%;
		border-spacing: 0;
	}

	table.def td,
	table.def th {
		padding: 0.5em;
		vertical-align: baseline;
		border-bottom: 1px solid #bbd7e9;
		border-bottom: 1px solid var(--defrow-border);
	}

	table.def > tbody > tr:last-child th,
	table.def > tbody > tr:last-child td {
		border-bottom: 0;
	}

	table.def th {
		font-style: italic;
		font-weight: normal;
		padding-left: 1em;
		width: 3em;
	}

	/* For when values are extra-complex and need formatting for readability */
	table td.pre {
		white-space: pre-wrap;
	}

	/* A footnote at the bottom of a def table */
	table.def td.footnote {
		padding-top: 0.6em;
	}
	table.def td.footnote::before {
		content: " ";
		display: block;
		height: 0.6em;
		width: 4em;
		border-top: thin solid;
	}

/** Data tables (and properly marked-up index tables) *************************/
	/*
		<table class="data"> highlights structural relationships in a table
		when correct markup is used (e.g. thead/tbody, th vs. td, scope attribute)

		Use class="complex data" for particularly complicated tables --
		(This will draw more lines: busier, but clearer.)

		Use class="long" on table cells with paragraph-like contents
		(This will adjust text alignment accordingly.)
		Alternately use class="longlastcol" on tables, to have the last column assume "long".
	*/

	table {
		word-wrap: normal;
		overflow-wrap: normal;
		hyphens: manual;
	}

	table.data,
	table.index {
		margin: 1em auto;
		border-collapse: collapse;
		border: hidden;
		width: 100%;
	}
	table.data caption,
	table.index caption {
		max-width: 50em;
		margin: 0 auto 1em;
	}

	table.data td,  table.data th,
	table.index td, table.index th {
		padding: 0.5em 1em;
		border-width: 1px;
		border-color: silver;
		border-color: var(--datacell-border);
		border-top-style: solid;
	}

	table.data thead td:empty {
		padding: 0;
		border: 0;
	}

	table.data  thead,
	table.index thead,
	table.data  tbody,
	table.index tbody {
		border-bottom: 2px solid;
	}

	table.data colgroup,
	table.index colgroup {
		border-left: 2px solid;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		border-right: 2px solid;
		border-top: 1px solid silver;
		border-top: 1px solid var(--datacell-border);
		padding-right: 1em;
	}

	table.data th[colspan],
	table.data td[colspan] {
		text-align: center;
	}

	table.complex.data th,
	table.complex.data td {
		border: 1px solid silver;
		border: 1px solid var(--datacell-border);
		text-align: center;
	}

	table.data.longlastcol td:last-child,
	table.data td.long {
		vertical-align: baseline;
		text-align: left;
	}

	table.data img {
		vertical-align: middle;
	}


/*
Alternate table alignment rules

	table.data,
	table.index {
		text-align: center;
	}

	table.data  thead th[scope="row"],
	table.index thead th[scope="row"] {
		text-align: right;
	}

	table.data  tbody th:first-child,
	table.index tbody th:first-child  {
		text-align: right;
	}

Possible extra rowspan handling

	table.data  tbody th[rowspan]:not([rowspan='1']),
	table.index tbody th[rowspan]:not([rowspan='1']),
	table.data  tbody td[rowspan]:not([rowspan='1']),
	table.index tbody td[rowspan]:not([rowspan='1']) {
		border-left: 1px solid silver;
	}

	table.data  tbody th[rowspan]:first-child,
	table.index tbody th[rowspan]:first-child,
	table.data  tbody td[rowspan]:first-child,
	table.index tbody td[rowspan]:first-child{
		border-left: 0;
		border-right: 1px solid silver;
	}
*/

/******************************************************************************/
/*                                  Indices                                   */
/******************************************************************************/


/** Table of Contents *********************************************************/

	.toc a {
		/* More spacing; use padding to make it part of the click target. */
		padding: 0.1rem 1px 0;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Switch to using border-bottom for underlines */
		text-decoration: none;
		border-bottom: 1px solid;
		/* Reverse color scheme */
		color: black;
		color: var(--toclink-text);
		border-color: #3980b5;
		border-color: var(--toclink-underline);
	}
	.toc a:visited {
		color: black;
		color: var(--toclink-visited-text);
		border-color: #054572;
		border-color: var(--toclink-visited-underline);
	}
	.toc a:focus,
	.toc a:hover {
		background: rgba(75%, 75%, 75%, .25);
		background: var(--a-hover-bg);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	.toc a:not(:focus):not(:hover) {
		/* Allow colors to cascade through from link styling */
		border-bottom-color: transparent;
	}

	.toc, .toc ol, .toc ul, .toc li {
		list-style: none; /* Numbers must be inlined into source */
		/* because generated content isn't search/selectable and markers can't do multilevel yet */
		margin:  0;
		padding: 0;
	}
	.toc {
		line-height: 1.1em;
	}

	/* ToC not indented until third level, but font style & margins show hierarchy */
	.toc > li			{ font-weight: bold;   }
	.toc > li li		 { font-weight: normal; }
	.toc > li li li	  { font-size:   95%;	}
	.toc > li li li li	{ font-size:   90%;	}
	.toc > li li li li li { font-size:   85%;	}

	/* @supports not (display:grid) { */
		.toc > li			{ margin: 1.5rem 0;	}
		.toc > li li		 { margin: 0.3rem 0;	}
		.toc > li li li	  { margin-left: 2rem;   }

		/* Section numbers in a column of their own */
		.toc .secno {
			float: left;
			width: 4rem;
			white-space: nowrap;
		}
		.toc > li li li li .secno { font-size: 85%; }
		.toc > li li li li li .secno { font-size: 100%; }

		.toc li {
			clear: both;
		}

		:not(li) > .toc			 { margin-left:  5rem; }
		.toc .secno				 { margin-left: -5rem; }
		.toc > li li li .secno	  { margin-left: -7rem; }
		.toc > li li li li .secno	{ margin-left: -9rem; }
		.toc > li li li li li .secno { margin-left: -11rem; }

		/* Tighten up indentation in narrow ToCs */
		@media (max-width: 30em) {
			:not(li) > .toc			 { margin-left:  4rem; }
			.toc .secno				 { margin-left: -4rem; }
			.toc > li li li			 { margin-left:  1rem; }
			.toc > li li li .secno	  { margin-left: -5rem; }
			.toc > li li li li .secno	{ margin-left: -6rem; }
			.toc > li li li li li .secno { margin-left: -7rem; }
		}
		/* Loosen it on wide screens */
		@media screen and (min-width: 78em) {
			body:not(.toc-inline) :not(li) > .toc			 { margin-left:  4rem; }
			body:not(.toc-inline) .toc .secno				 { margin-left: -4rem; }
			body:not(.toc-inline) .toc > li li li			 { margin-left:  1rem; }
			body:not(.toc-inline) .toc > li li li .secno	  { margin-left: -5rem; }
			body:not(.toc-inline) .toc > li li li li .secno	{ margin-left: -6rem; }
			body:not(.toc-inline) .toc > li li li li li .secno { margin-left: -7rem; }
	}
	/* } */

	@supports (display:grid) and (display:contents) {
		/* Use #toc over .toc to override non-@supports rules. */
		#toc {
			display: grid;
			align-content: start;
			grid-template-columns: auto 1fr;
			grid-column-gap: 1rem;
			column-gap: 1rem;
			grid-row-gap: .6rem;
			row-gap: .6rem;
		}
		#toc h2 {
			grid-column: 1 / -1;
			margin-bottom: 0;
		}
		#toc ol,
		#toc li,
		#toc a {
			display: contents;
			/* Switch <a> to subgrid when supported */
		}
		#toc span {
			margin: 0;
		}
		#toc > .toc > li > a > span {
			/* The spans of the top-level list,
			  comprising the first items of each top-level section. */
			margin-top: 1.1rem;
		}
		#toc#toc .secno { /* Ugh, need more specificity to override base.css */
			grid-column: 1;
			width: auto;
			margin-left: 0;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
			border-bottom: 3px solid transparent;
			margin-bottom: -3px;
		}
		#toc .content:hover,
		#toc .content:focus {
			background: rgba(75%, 75%, 75%, .25);
			background: var(--a-hover-bg);
			border-bottom-color: #054572;
			border-bottom-color: var(--toclink-underline);
		}
		#toc li li li .content {
			margin-left: 1rem;
		}
		#toc li li li li .content {
			margin-left: 2rem;
		}
	}


/** Index *********************************************************************/

	/* Index Lists: Layout */
	ul.index	  { margin-left: 0; columns: 15em; text-indent: 1em hanging; }
	ul.index li	{ margin-left: 0; list-style: none; break-inside: avoid; }
	ul.index li li { margin-left: 1em; }
	ul.index dl	{ margin-top: 0; }
	ul.index dt	{ margin: .2em 0 .2em 20px;}
	ul.index dd	{ margin: .2em 0 .2em 40px;}
	/* Index Lists: Typography */
	ul.index ul,
	ul.index dl { font-size: smaller; }
	@media not print {
		ul.index li a + span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
			color: var(--indexinfo-text);
		}
	}

/** Index Tables *****************************************************/
	/* See also the data table styling section, which this effectively subclasses */

	table.index {
		font-size: small;
		border-collapse: collapse;
		border-spacing: 0;
		text-align: left;
		margin: 1em 0;
	}

	table.index td,
	table.index th {
		padding: 0.4em;
	}

	table.index tr:hover td:not([rowspan]),
	table.index tr:hover th:not([rowspan]) {
		color: black;
		color: var(--indextable-hover-text);
		background: #f7f8f9;
		background: var(--indextable-hover-bg);
	}

	/* The link in the first column in the property table (formerly a TD) */
	table.index th:first-child a {
		font-weight: bold;
	}

/** Outdated warning **********************************************************/

.outdated-spec {
	color: black;
	color: var(--outdatedspec-text);
	background-color: rgba(0,0,0,0.5);
	background-color: var(--outdatedspec-bg);
}

.outdated-warning {
	position: fixed;
	bottom: 50%;
	left: 0;
	right: 0;
	margin: 0 auto;
	width: 50%;
	background: maroon;
	background: var(--outdated-bg);
	color: white;
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	color: var(--outdated-text);
	border-radius: 1em;
	box-shadow: 0 0 1em red;
	box-shadow: 0 0 1em var(--outdated-shadow);
	padding: 2em;
	text-align: center;
	z-index: 2;
}

.outdated-warning a {
	color: currentcolor;
	background: transparent;
}

.edited-rec-warning {
	background: darkorange;
	background: var(--editedrec-bg);
	box-shadow: 0 0 1em;
}

.outdated-warning button {
	position: absolute;
	top: 0;
	right:0;
	margin: 0;
	border: 0;
	padding: 0.25em 0.5em;
	background: transparent;
	color: white;
	color: var(--outdated-text);
	font:1em sans-serif;
	text-align:center;
}

.outdated-warning span {
	display: block;
}

.outdated-collapsed {
	bottom: 0;
	border-radius: 0;
	width: 100%;
	padding: 0;
}

/******************************************************************************/
/*                                    Print                                   */
/******************************************************************************/

	@media print {
		/* Pages have their own margins. */
		html {
			margin: 0;
		}
		/* Serif for print. */
		body {
			font-family: serif;
		}

		.outdated-warning {
			position: absolute;
			border-style: solid;
			border-color: red;
		}

		.outdated-warning input {
			display: none;
		}
	}
	@page {
		margin: 1.5cm 1.1cm;
	}



/******************************************************************************/
/*                             Overflow Control                               */
/******************************************************************************/

	.figure .caption, .sidefigure .caption, figcaption {
		/* in case figure is overlarge, limit caption to 50em */
		max-width: 50rem;
		margin-left: auto;
		margin-right: auto;
	}
	.overlarge {
		/* Magic to create good item positioning:
		  "content column" is 50ems wide at max; less on smaller screens.
		  Extra space (after ToC + content) is empty on the right.

		  1. When item < content column, centers item in column.
		  2. When content < item < available, left-aligns.
		  3. When item > available, fills available + scroll bar.
		*/
		display: grid;
		grid-template-columns: minmax(0, 50em);
	}
	.overlarge > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-right: calc(13px + 26.5rem - 50vw);
			max-width: none;
		}
	}
	@media screen and (min-width: 78em) {
		body:not(.toc-inline) .overlarge {
			/* 30.5em body padding 50em content area */
			margin-right: calc(40em - 50vw) !important;
		}
	}
	@media screen and (min-width: 90em) {
		body:not(.toc-inline) .overlarge {
			/* 4em html margin 30.5em body padding 50em content area */
			margin-right: calc(84.5em - 100vw) !important;
		}
	}

	@media not print {
		.overlarge {
			overflow-x: auto;
			/* See Lea Verou's explanation background-attachment:
			* http://lea.verou.me/2012/04/background-attachment-local/
			*
			background: top left  / 4em 100% linear-gradient(to right,  #ffffff, rgba(255, 255, 255, 0)) local,
						top right / 4em 100% linear-gradient(to left, #ffffff, rgba(255, 255, 255, 0)) local,
						top left  / 1em 100% linear-gradient(to right,  #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						top right / 1em 100% linear-gradient(to left, #c3c3c5, rgba(195, 195, 197, 0)) scroll,
						white;
			background-repeat: no-repeat;
			*/
		}
	}
</style>
<style>
    table, th, td {
      border: 1px solid black;
      border-collapse: collapse;
      vertical-align: top;
    }
    th, td {
      border-left: none;
      border-right: none;
      padding: 0px 10px;
    }
    th {
      text-align: center;
    }

    del { background: #fcc; color: #000; text-decoration: line-through; }
    ins { background: #cfc; color: #000; }
    blockquote .highlight:not(.idl) { background: initial; margin: initial; padding: 0.5em }
    blockquote ul { background: inherit; }
    blockquote code.highlight:not(.idl) { padding: initial; }
    blockquote c-[a] { color: inherit; } /* Keyword.Declaration */
    blockquote c-[b] { color: inherit; } /* Keyword.Type */
    blockquote c-[c] { color: inherit; } /* Comment */
    blockquote c-[d] { color: inherit; } /* Comment.Multiline */
    blockquote c-[e] { color: inherit; } /* Name.Attribute */
    blockquote c-[f] { color: inherit; } /* Name.Tag */
    blockquote c-[g] { color: inherit; } /* Name.Variable */
    blockquote c-[k] { color: inherit; } /* Keyword */
    blockquote c-[l] { color: inherit; } /* Literal */
    blockquote c-[m] { color: inherit; } /* Literal.Number */
    blockquote c-[n] { color: inherit; } /* Name */
    blockquote c-[o] { color: inherit; } /* Operator */
    blockquote c-[p] { color: inherit; } /* Punctuation */
    blockquote c-[s] { color: inherit; } /* Literal.String */
    blockquote c-[t] { color: inherit; } /* Literal.String.Single */
    blockquote c-[u] { color: inherit; } /* Literal.String.Double */
    blockquote c-[cp] { color: inherit; } /* Comment.Preproc */
    blockquote c-[c1] { color: inherit; } /* Comment.Single */
    blockquote c-[cs] { color: inherit; } /* Comment.Special */
    blockquote c-[kc] { color: inherit; } /* Keyword.Constant */
    blockquote c-[kn] { color: inherit; } /* Keyword.Namespace */
    blockquote c-[kp] { color: inherit; } /* Keyword.Pseudo */
    blockquote c-[kr] { color: inherit; } /* Keyword.Reserved */
    blockquote c-[ld] { color: inherit; } /* Literal.Date */
    blockquote c-[nc] { color: inherit; } /* Name.Class */
    blockquote c-[no] { color: inherit; } /* Name.Constant */
    blockquote c-[nd] { color: inherit; } /* Name.Decorator */
    blockquote c-[ni] { color: inherit; } /* Name.Entity */
    blockquote c-[ne] { color: inherit; } /* Name.Exception */
    blockquote c-[nf] { color: inherit; } /* Name.Function */
    blockquote c-[nl] { color: inherit; } /* Name.Label */
    blockquote c-[nn] { color: inherit; } /* Name.Namespace */
    blockquote c-[py] { color: inherit; } /* Name.Property */
    blockquote c-[ow] { color: inherit; } /* Operator.Word */
    blockquote c-[mb] { color: inherit; } /* Literal.Number.Bin */
    blockquote c-[mf] { color: inherit; } /* Literal.Number.Float */
    blockquote c-[mh] { color: inherit; } /* Literal.Number.Hex */
    blockquote c-[mi] { color: inherit; } /* Literal.Number.Integer */
    blockquote c-[mo] { color: inherit; } /* Literal.Number.Oct */
    blockquote c-[sb] { color: inherit; } /* Literal.String.Backtick */
    blockquote c-[sc] { color: inherit; } /* Literal.String.Char */
    blockquote c-[sd] { color: inherit; } /* Literal.String.Doc */
    blockquote c-[se] { color: inherit; } /* Literal.String.Escape */
    blockquote c-[sh] { color: inherit; } /* Literal.String.Heredoc */
    blockquote c-[si] { color: inherit; } /* Literal.String.Interpol */
    blockquote c-[sx] { color: inherit; } /* Literal.String.Other */
    blockquote c-[sr] { color: inherit; } /* Literal.String.Regex */
    blockquote c-[ss] { color: inherit; } /* Literal.String.Symbol */
    blockquote c-[vc] { color: inherit; } /* Name.Variable.Class */
    blockquote c-[vg] { color: inherit; } /* Name.Variable.Global */
    blockquote c-[vi] { color: inherit; } /* Name.Variable.Instance */
    blockquote c-[il] { color: inherit; } /* Literal.Number.Integer.Long */
  </style>
  <meta content="Bikeshed version 4b8aed3f7, updated Thu Mar 6 12:35:01 2025 -0800" name="generator">
  <link href="https://eisenwave.github.io/cpp-proposals/bit-permutations.html" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
  <meta content="e2b08c460e7f642b7d003d5233e7bcbfd7720b61" name="revision">
  <meta content="dark light" name="color-scheme">
<style>
@media (prefers-color-scheme: dark) {
  c-[mb], c-[mi], c-[mh] {
    color: #d59393 !important;
  }

  blockquote c-[mb], blockquote c-[mi], blockquote c-[mh] {
    color: var(--text) !important;
  }
}

.indent {
    margin-left: 2em;
}

svg {
    background: none;
    vertical-align: middle;
}

ins {
    background: rgba(136, 255, 93, 0.2);
    color: inherit;
    text-decoration: underlined;
}
del {
    background: rgba(255, 93, 93, 0.2);
    color: inherit;
    text-decoration: strikethrough;
}

math[display=inline] {
    margin: 0 auto;
    font-size: 110%;
}
math {
    font-size: 120%;
}

.ins-block {
    margin: 1em auto;
    padding: 1em;
    
    border: .5em;
    border-left-style: solid;
    border-color: rgb(89, 159, 64);

    page-break-inside: avoid;
    display: block;
    background: rgba(136, 255, 93, 0.1);
}

.ins-block pre {
    padding: 0 !important;
    margin: 0 !important;
    background: none !important;
}

p- {
    display: block;
    margin-top: 0.5em;
    margin-bottom: 0.5em;
}
</style>
<style>
th, td, table {
    border: 1px solid var(--text);
}
th, td {
    border-left-width: 0;
    border-right-width: 0;
}

table td:nth-child(10n-9), th {
    font-weight: bold;
    background-color: color-mix(in srgb, var(--text) 5%, transparent);
}
</style>
<style>
.subclause-title {
    display: grid;
    grid-template-columns: 1fr auto;
}

.formula {
    display: grid;
    grid-template-columns: 1fr auto;
    padding-left: 4em;
}
</style>
<style>/* Boilerplate: style-autolinks */
.css.css, .property.property, .descriptor.descriptor {
    color: var(--a-normal-text);
    font-size: inherit;
    font-family: inherit;
}
.css::before, .property::before, .descriptor::before {
    content: "‘";
}
.css::after, .property::after, .descriptor::after {
    content: "’";
}
.property, .descriptor {
    /* Don't wrap property and descriptor names */
    white-space: nowrap;
}
.type { /* CSS value <type> */
    font-style: italic;
}
pre .property::before, pre .property::after {
    content: "";
}
[data-link-type="property"]::before,
[data-link-type="propdesc"]::before,
[data-link-type="descriptor"]::before,
[data-link-type="value"]::before,
[data-link-type="function"]::before,
[data-link-type="at-rule"]::before,
[data-link-type="selector"]::before,
[data-link-type="maybe"]::before {
    content: "‘";
}
[data-link-type="property"]::after,
[data-link-type="propdesc"]::after,
[data-link-type="descriptor"]::after,
[data-link-type="value"]::after,
[data-link-type="function"]::after,
[data-link-type="at-rule"]::after,
[data-link-type="selector"]::after,
[data-link-type="maybe"]::after {
    content: "’";
}

[data-link-type].production::before,
[data-link-type].production::after,
.prod [data-link-type]::before,
.prod [data-link-type]::after {
    content: "";
}

[data-link-type=element],
[data-link-type=element-attr] {
    font-family: Menlo, Consolas, "DejaVu Sans Mono", monospace;
    font-size: .9em;
}
[data-link-type=element]::before { content: "<" }
[data-link-type=element]::after  { content: ">" }

[data-link-type=biblio] {
    white-space: pre;
}

@media (prefers-color-scheme: dark) {
    :root {
        --selflink-text: black;
        --selflink-bg: silver;
        --selflink-hover-text: white;
    }
}
</style>
<style>/* Boilerplate: style-colors */
/* Any --*-text not paired with a --*-bg is assumed to have a transparent bg */
:root {
    color-scheme: light dark;

    --text: black;
    --bg: white;

    --unofficial-watermark: url(https://www.w3.org/StyleSheets/TR/2016/logos/UD-watermark);

    --logo-bg: #1a5e9a;
    --logo-active-bg: #c00;
    --logo-text: white;

    --tocnav-normal-text: #707070;
    --tocnav-normal-bg: var(--bg);
    --tocnav-hover-text: var(--tocnav-normal-text);
    --tocnav-hover-bg: #f8f8f8;
    --tocnav-active-text: #c00;
    --tocnav-active-bg: var(--tocnav-normal-bg);

    --tocsidebar-text: var(--text);
    --tocsidebar-bg: #f7f8f9;
    --tocsidebar-shadow: rgba(0,0,0,.1);
    --tocsidebar-heading-text: hsla(203,20%,40%,.7);

    --toclink-text: var(--text);
    --toclink-underline: #3980b5;
    --toclink-visited-text: var(--toclink-text);
    --toclink-visited-underline: #054572;

    --heading-text: #005a9c;

    --hr-text: var(--text);

    --algo-border: #def;

    --del-text: red;
    --del-bg: transparent;
    --ins-text: #080;
    --ins-bg: transparent;

    --a-normal-text: #034575;
    --a-normal-underline: #bbb;
    --a-visited-text: var(--a-normal-text);
    --a-visited-underline: #707070;
    --a-hover-bg: rgba(75%, 75%, 75%, .25);
    --a-active-text: #c00;
    --a-active-underline: #c00;

    --blockquote-border: silver;
    --blockquote-bg: transparent;
    --blockquote-text: currentcolor;

    --issue-border: #e05252;
    --issue-bg: #fbe9e9;
    --issue-text: var(--text);
    --issueheading-text: #831616;

    --example-border: #e0cb52;
    --example-bg: #fcfaee;
    --example-text: var(--text);
    --exampleheading-text: #574b0f;

    --note-border: #52e052;
    --note-bg: #e9fbe9;
    --note-text: var(--text);
    --noteheading-text: hsl(120, 70%, 30%);
    --notesummary-underline: silver;

    --assertion-border: #aaa;
    --assertion-bg: #eee;
    --assertion-text: black;

    --advisement-border: orange;
    --advisement-bg: #fec;
    --advisement-text: var(--text);
    --advisementheading-text: #b35f00;

    --warning-border: red;
    --warning-bg: hsla(40,100%,50%,0.95);
    --warning-text: var(--text);

    --amendment-border: #330099;
    --amendment-bg: #F5F0FF;
    --amendment-text: var(--text);
    --amendmentheading-text: #220066;

    --def-border: #8ccbf2;
    --def-bg: #def;
    --def-text: var(--text);
    --defrow-border: #bbd7e9;

    --datacell-border: silver;

    --indexinfo-text: #707070;

    --indextable-hover-text: black;
    --indextable-hover-bg: #f7f8f9;

    --outdatedspec-bg: rgba(0, 0, 0, .5);
    --outdatedspec-text: black;
    --outdated-bg: maroon;
    --outdated-text: white;
    --outdated-shadow: red;

    --editedrec-bg: darkorange;
}

@media (prefers-color-scheme: dark) {
    :root {
        --text: #ddd;
        --bg: black;

        --unofficial-watermark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='400' height='400'%3E%3Cg fill='%23100808' transform='translate(200 200) rotate(-45) translate(-200 -200)' stroke='%23100808' stroke-width='3'%3E%3Ctext x='50%25' y='220' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EUNOFFICIAL%3C/text%3E%3Ctext x='50%25' y='305' style='font: bold 70px sans-serif; text-anchor: middle; letter-spacing: 6px;'%3EDRAFT%3C/text%3E%3C/g%3E%3C/svg%3E");

        --logo-bg: #1a5e9a;
        --logo-active-bg: #c00;
        --logo-text: white;

        --tocnav-normal-text: #999;
        --tocnav-normal-bg: var(--bg);
        --tocnav-hover-text: var(--tocnav-normal-text);
        --tocnav-hover-bg: #080808;
        --tocnav-active-text: #f44;
        --tocnav-active-bg: var(--tocnav-normal-bg);

        --tocsidebar-text: var(--text);
        --tocsidebar-bg: #080808;
        --tocsidebar-shadow: rgba(255,255,255,.1);
        --tocsidebar-heading-text: hsla(203,20%,40%,.7);

        --toclink-text: var(--text);
        --toclink-underline: #6af;
        --toclink-visited-text: var(--toclink-text);
        --toclink-visited-underline: #054572;

        --heading-text: #8af;

        --hr-text: var(--text);

        --algo-border: #456;

        --del-text: #f44;
        --del-bg: transparent;
        --ins-text: #4a4;
        --ins-bg: transparent;

        --a-normal-text: #6af;
        --a-normal-underline: #555;
        --a-visited-text: var(--a-normal-text);
        --a-visited-underline: var(--a-normal-underline);
        --a-hover-bg: rgba(25%, 25%, 25%, .2);
        --a-active-text: #f44;
        --a-active-underline: var(--a-active-text);

        --borderedblock-bg: rgba(255, 255, 255, .05);

        --blockquote-border: silver;
        --blockquote-bg: var(--borderedblock-bg);
        --blockquote-text: currentcolor;

        --issue-border: #e05252;
        --issue-bg: var(--borderedblock-bg);
        --issue-text: var(--text);
        --issueheading-text: hsl(0deg, 70%, 70%);

        --example-border: hsl(50deg, 90%, 60%);
        --example-bg: var(--borderedblock-bg);
        --example-text: var(--text);
        --exampleheading-text: hsl(50deg, 70%, 70%);

        --note-border: hsl(120deg, 100%, 35%);
        --note-bg: var(--borderedblock-bg);
        --note-text: var(--text);
        --noteheading-text: hsl(120, 70%, 70%);
        --notesummary-underline: silver;

        --assertion-border: #444;
        --assertion-bg: var(--borderedblock-bg);
        --assertion-text: var(--text);

        --advisement-border: orange;
        --advisement-bg: #222218;
        --advisement-text: var(--text);
        --advisementheading-text: #f84;

        --warning-border: red;
        --warning-bg: hsla(40,100%,20%,0.95);
        --warning-text: var(--text);

        --amendment-border: #330099;
        --amendment-bg: #080010;
        --amendment-text: var(--text);
        --amendmentheading-text: #cc00ff;

        --def-border: #8ccbf2;
        --def-bg: #080818;
        --def-text: var(--text);
        --defrow-border: #136;

        --datacell-border: silver;

        --indexinfo-text: #aaa;

        --indextable-hover-text: var(--text);
        --indextable-hover-bg: #181818;

        --outdatedspec-bg: rgba(255, 255, 255, .5);
        --outdatedspec-text: black;
        --outdated-bg: maroon;
        --outdated-text: white;
        --outdated-shadow: red;

        --editedrec-bg: darkorange;
    }
    /* In case a transparent-bg image doesn't expect to be on a dark bg,
       which is quite common in practice... */
    img { background: white; }
}
</style>
<style>/* Boilerplate: style-counters */
body {
    counter-reset: example figure issue;
}
.issue {
    counter-increment: issue;
}
.issue:not(.no-marker)::before {
    content: "Issue " counter(issue);
}

.example {
    counter-increment: example;
}
.example:not(.no-marker)::before {
    content: "Example " counter(example);
}
.invalid.example:not(.no-marker)::before,
.illegal.example:not(.no-marker)::before {
    content: "Invalid Example" counter(example);
}

figcaption {
    counter-increment: figure;
}
figcaption:not(.no-marker)::before {
    content: "Figure " counter(figure) " ";
}
</style>
<style>/* Boilerplate: style-issues */
a[href].issue-return {
    float: right;
    float: inline-end;
    color: var(--issueheading-text);
    font-weight: bold;
    text-decoration: none;
}
</style>
<style>/* Boilerplate: style-md-lists */
/* This is a weird hack for me not yet following the commonmark spec
   regarding paragraph and lists. */
[data-md] > :first-child {
    margin-top: 0;
}
[data-md] > :last-child {
    margin-bottom: 0;
}
</style>
<style>/* Boilerplate: style-selflinks */
:root {
    --selflink-text: white;
    --selflink-bg: gray;
    --selflink-hover-text: black;
}
.heading, .issue, .note, .example, li, dt {
    position: relative;
}
a.self-link {
    position: absolute;
    top: 0;
    left: calc(-1 * (3.5rem - 26px));
    width: calc(3.5rem - 26px);
    height: 2em;
    text-align: center;
    border: none;
    transition: opacity .2s;
    opacity: .5;
}
a.self-link:hover {
    opacity: 1;
}
.heading > a.self-link {
    font-size: 83%;
}
.example > a.self-link,
.note > a.self-link,
.issue > a.self-link {
    /* These blocks are overflow:auto, so positioning outside
       doesn't work. */
    left: auto;
    right: 0;
}
li > a.self-link {
    left: calc(-1 * (3.5rem - 26px) - 2em);
}
dfn > a.self-link {
    top: auto;
    left: auto;
    opacity: 0;
    width: 1.5em;
    height: 1.5em;
    background: var(--selflink-bg);
    color: var(--selflink-text);
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: var(--selflink-hover-text);
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }
</style>
<style>/* Boilerplate: style-syntax-highlighting */
code.highlight { padding: .1em; border-radius: .3em; }
pre.highlight, pre > code.highlight { display: block; padding: 1em; margin: .5em 0; overflow: auto; border-radius: 0; }

.highlight:not(.idl) { background: rgba(0, 0, 0, .03); }
c-[a] { color: #990055 } /* Keyword.Declaration */
c-[b] { color: #990055 } /* Keyword.Type */
c-[c] { color: #708090 } /* Comment */
c-[d] { color: #708090 } /* Comment.Multiline */
c-[e] { color: #0077aa } /* Name.Attribute */
c-[f] { color: #669900 } /* Name.Tag */
c-[g] { color: #222222 } /* Name.Variable */
c-[k] { color: #990055 } /* Keyword */
c-[l] { color: #000000 } /* Literal */
c-[m] { color: #000000 } /* Literal.Number */
c-[n] { color: #0077aa } /* Name */
c-[o] { color: #999999 } /* Operator */
c-[p] { color: #999999 } /* Punctuation */
c-[s] { color: #a67f59 } /* Literal.String */
c-[t] { color: #a67f59 } /* Literal.String.Single */
c-[u] { color: #a67f59 } /* Literal.String.Double */
c-[cp] { color: #708090 } /* Comment.Preproc */
c-[c1] { color: #708090 } /* Comment.Single */
c-[cs] { color: #708090 } /* Comment.Special */
c-[kc] { color: #990055 } /* Keyword.Constant */
c-[kn] { color: #990055 } /* Keyword.Namespace */
c-[kp] { color: #990055 } /* Keyword.Pseudo */
c-[kr] { color: #990055 } /* Keyword.Reserved */
c-[ld] { color: #000000 } /* Literal.Date */
c-[nc] { color: #0077aa } /* Name.Class */
c-[no] { color: #0077aa } /* Name.Constant */
c-[nd] { color: #0077aa } /* Name.Decorator */
c-[ni] { color: #0077aa } /* Name.Entity */
c-[ne] { color: #0077aa } /* Name.Exception */
c-[nf] { color: #0077aa } /* Name.Function */
c-[nl] { color: #0077aa } /* Name.Label */
c-[nn] { color: #0077aa } /* Name.Namespace */
c-[py] { color: #0077aa } /* Name.Property */
c-[ow] { color: #999999 } /* Operator.Word */
c-[mb] { color: #000000 } /* Literal.Number.Bin */
c-[mf] { color: #000000 } /* Literal.Number.Float */
c-[mh] { color: #000000 } /* Literal.Number.Hex */
c-[mi] { color: #000000 } /* Literal.Number.Integer */
c-[mo] { color: #000000 } /* Literal.Number.Oct */
c-[sb] { color: #a67f59 } /* Literal.String.Backtick */
c-[sc] { color: #a67f59 } /* Literal.String.Char */
c-[sd] { color: #a67f59 } /* Literal.String.Doc */
c-[se] { color: #a67f59 } /* Literal.String.Escape */
c-[sh] { color: #a67f59 } /* Literal.String.Heredoc */
c-[si] { color: #a67f59 } /* Literal.String.Interpol */
c-[sx] { color: #a67f59 } /* Literal.String.Other */
c-[sr] { color: #a67f59 } /* Literal.String.Regex */
c-[ss] { color: #a67f59 } /* Literal.String.Symbol */
c-[vc] { color: #0077aa } /* Name.Variable.Class */
c-[vg] { color: #0077aa } /* Name.Variable.Global */
c-[vi] { color: #0077aa } /* Name.Variable.Instance */
c-[il] { color: #000000 } /* Literal.Number.Integer.Long */

@media (prefers-color-scheme: dark) {
    .highlight:not(.idl) { background: rgba(255, 255, 255, .05); }

    c-[a] { color: #d33682 } /* Keyword.Declaration */
    c-[b] { color: #d33682 } /* Keyword.Type */
    c-[c] { color: #2aa198 } /* Comment */
    c-[d] { color: #2aa198 } /* Comment.Multiline */
    c-[e] { color: #268bd2 } /* Name.Attribute */
    c-[f] { color: #b58900 } /* Name.Tag */
    c-[g] { color: #cb4b16 } /* Name.Variable */
    c-[k] { color: #d33682 } /* Keyword */
    c-[l] { color: #657b83 } /* Literal */
    c-[m] { color: #657b83 } /* Literal.Number */
    c-[n] { color: #268bd2 } /* Name */
    c-[o] { color: #657b83 } /* Operator */
    c-[p] { color: #657b83 } /* Punctuation */
    c-[s] { color: #6c71c4 } /* Literal.String */
    c-[t] { color: #6c71c4 } /* Literal.String.Single */
    c-[u] { color: #6c71c4 } /* Literal.String.Double */
    c-[ch] { color: #2aa198 } /* Comment.Hashbang */
    c-[cp] { color: #2aa198 } /* Comment.Preproc */
    c-[cpf] { color: #2aa198 } /* Comment.PreprocFile */
    c-[c1] { color: #2aa198 } /* Comment.Single */
    c-[cs] { color: #2aa198 } /* Comment.Special */
    c-[kc] { color: #d33682 } /* Keyword.Constant */
    c-[kn] { color: #d33682 } /* Keyword.Namespace */
    c-[kp] { color: #d33682 } /* Keyword.Pseudo */
    c-[kr] { color: #d33682 } /* Keyword.Reserved */
    c-[ld] { color: #657b83 } /* Literal.Date */
    c-[nc] { color: #268bd2 } /* Name.Class */
    c-[no] { color: #268bd2 } /* Name.Constant */
    c-[nd] { color: #268bd2 } /* Name.Decorator */
    c-[ni] { color: #268bd2 } /* Name.Entity */
    c-[ne] { color: #268bd2 } /* Name.Exception */
    c-[nf] { color: #268bd2 } /* Name.Function */
    c-[nl] { color: #268bd2 } /* Name.Label */
    c-[nn] { color: #268bd2 } /* Name.Namespace */
    c-[py] { color: #268bd2 } /* Name.Property */
    c-[ow] { color: #657b83 } /* Operator.Word */
    c-[mb] { color: #657b83 } /* Literal.Number.Bin */
    c-[mf] { color: #657b83 } /* Literal.Number.Float */
    c-[mh] { color: #657b83 } /* Literal.Number.Hex */
    c-[mi] { color: #657b83 } /* Literal.Number.Integer */
    c-[mo] { color: #657b83 } /* Literal.Number.Oct */
    c-[sa] { color: #6c71c4 } /* Literal.String.Affix */
    c-[sb] { color: #6c71c4 } /* Literal.String.Backtick */
    c-[sc] { color: #6c71c4 } /* Literal.String.Char */
    c-[dl] { color: #6c71c4 } /* Literal.String.Delimiter */
    c-[sd] { color: #6c71c4 } /* Literal.String.Doc */
    c-[se] { color: #6c71c4 } /* Literal.String.Escape */
    c-[sh] { color: #6c71c4 } /* Literal.String.Heredoc */
    c-[si] { color: #6c71c4 } /* Literal.String.Interpol */
    c-[sx] { color: #6c71c4 } /* Literal.String.Other */
    c-[sr] { color: #6c71c4 } /* Literal.String.Regex */
    c-[ss] { color: #6c71c4 } /* Literal.String.Symbol */
    c-[fm] { color: #268bd2 } /* Name.Function.Magic */
    c-[vc] { color: #cb4b16 } /* Name.Variable.Class */
    c-[vg] { color: #cb4b16 } /* Name.Variable.Global */
    c-[vi] { color: #cb4b16 } /* Name.Variable.Instance */
    c-[vm] { color: #cb4b16 } /* Name.Variable.Magic */
    c-[il] { color: #657b83 } /* Literal.Number.Integer.Long */
}
</style>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P3104R4<br>Bit permutations</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="profile-and-date"><span class="content">Published Proposal, <time class="dt-updated" datetime="2025-06-28">2025-06-28</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://eisenwave.github.io/cpp-proposals/bit-permutations.html">https://eisenwave.github.io/cpp-proposals/bit-permutations.html</a>
     <dt class="editor">Author:
     <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:janschultke@gmail.com">Jan Schultke</a>
     <dt>Audience:
     <dd>SG6, LWG
     <dt>Project:
     <dd>ISO/IEC 14882 Programming Languages — C++, ISO/IEC JTC1/SC22/WG21
     <dt>Source:
     <dd><a href="https://github.com/Eisenwave/cpp-proposals/blob/master/src/bit-permutations.bs">eisenwave/cpp-proposals</a>
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <div class="p-summary" data-fill-with="abstract">
   <h2 class="no-num no-toc no-ref heading settled" id="abstract"><span class="content">Abstract</span></h2>
   <p>Add bit permutation functions to the bit manipulation library.</p>
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#revisions"><span class="secno">1</span> <span class="content">Revision history</span></a>
     <ol class="toc">
      <li><a href="#changes-since-r3"><span class="secno">1.1</span> <span class="content">Changes since R3</span></a>
      <li><a href="#changes-since-r2"><span class="secno">1.2</span> <span class="content">Changes since R2</span></a>
      <li><a href="#changes-since-r1"><span class="secno">1.3</span> <span class="content">Changes since R1</span></a>
      <li><a href="#changes-since-r0"><span class="secno">1.4</span> <span class="content">Changes since R0</span></a>
     </ol>
    <li><a href="#intro"><span class="secno">2</span> <span class="content">Introduction</span></a>
    <li>
     <a href="#proposed-features"><span class="secno">3</span> <span class="content">Proposed features</span></a>
     <ol class="toc">
      <li><a href="#intro-bit-reverse"><span class="secno">3.1</span> <span class="content"><code class="highlight"><c- n>bit_reverse</c-></code></span></a>
      <li><a href="#intro-bit-repeat"><span class="secno">3.2</span> <span class="content"><code class="highlight"><c- n>bit_repeat</c-></code></span></a>
      <li><a href="#intro-bit-compress"><span class="secno">3.3</span> <span class="content"><code class="highlight"><c- n>bit_compress</c-></code></span></a>
      <li><a href="#intro-bit-expand"><span class="secno">3.4</span> <span class="content"><code class="highlight"><c- n>bit_expand</c-></code></span></a>
     </ol>
    <li>
     <a href="#motivation-and-scope"><span class="secno">4</span> <span class="content">Motivation and scope</span></a>
     <ol class="toc">
      <li>
       <a href="#applications"><span class="secno">4.1</span> <span class="content">Applications</span></a>
       <ol class="toc">
        <li><a href="#applications-of-bit-reverse"><span class="secno">4.1.1</span> <span class="content">Applications of <code class="highlight"><c- n>bit_reverse</c-></code></span></a>
        <li><a href="#applications-of-bit-repeat"><span class="secno">4.1.2</span> <span class="content">Applications of <code class="highlight"><c- n>bit_repeat</c-></code></span></a>
        <li><a href="#applications-of-bit-compress-and-bit-expand"><span class="secno">4.1.3</span> <span class="content">Applications of <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span></a>
       </ol>
      <li>
       <a href="#use-cases"><span class="secno">4.2</span> <span class="content">Motivating examples</span></a>
       <ol class="toc">
        <li><a href="#implementing-countr-zero"><span class="secno">4.2.1</span> <span class="content">Implementing <code class="highlight"><c- n>countr_zero</c-></code> with <code class="highlight"><c- n>bit_repeat</c-></code></span></a>
        <li><a href="#interleaving-bits"><span class="secno">4.2.2</span> <span class="content">Interleaving bits with <code class="highlight"><c- n>bit_expand</c-></code></span></a>
        <li><a href="#input-output"><span class="secno">4.2.3</span> <span class="content">UTF-8 decoding with <code class="highlight"><c- n>bit_compress</c-></code></span></a>
        <li><a href="#building-operations"><span class="secno">4.2.4</span> <span class="content">Other operations based on <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span></a>
       </ol>
      <li>
       <a href="#hardware-support"><span class="secno">4.3</span> <span class="content">Hardware support</span></a>
       <ol class="toc">
        <li><a href="#hardware-support-reverse"><span class="secno">4.3.1</span> <span class="content">Support for <code class="highlight"><c- n>bit_reverse</c-></code></span></a>
        <li><a href="#hardware-support-bit-repeat"><span class="secno">4.3.2</span> <span class="content">Support for <code class="highlight"><c- n>bit_repeat</c-></code></span></a>
        <li><a href="#hardware-support-compress-expand"><span class="secno">4.3.3</span> <span class="content">Support for <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span></a>
       </ol>
     </ol>
    <li><a href="#impact-on-existing-code"><span class="secno">5</span> <span class="content">Impact on existing code</span></a>
    <li>
     <a href="#design"><span class="secno">6</span> <span class="content">Design considerations</span></a>
     <ol class="toc">
      <li><a href="#bit-repeat-signature"><span class="secno">6.1</span> <span class="content">Signature of <code class="highlight"><c- n>bit_repeat</c-></code></span></a>
      <li><a href="#naming-compress-expand"><span class="secno">6.2</span> <span class="content">Why the names <em>compress</em> and <em>expand</em>?</span></a>
      <li>
       <a href="#further-generalization"><span class="secno">6.3</span> <span class="content">Why the lack of generalization?</span></a>
       <ol class="toc">
        <li><a href="#generalized-compress-expand"><span class="secno">6.3.1</span> <span class="content">No generalized <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span></a>
        <li><a href="#generalized-bit-reverse"><span class="secno">6.3.2</span> <span class="content">No generalized <code class="highlight"><c- n>bit_reverse</c-></code></span></a>
       </ol>
      <li><a href="#unusual-signature"><span class="secno">6.4</span> <span class="content">Why does the signature of <code class="highlight"><c- n>bit_compress</c-></code> require two same <code class="highlight"><c- n>T</c-></code>s?</span></a>
      <li><a href="#no-left-compress-expand"><span class="secno">6.5</span> <span class="content">Why no left variant for <code class="highlight"><c- n>bit_compress</c-></code>?</span></a>
      <li><a href="#why-no-simd"><span class="secno">6.6</span> <span class="content">Why no SIMD support?</span></a>
     </ol>
    <li>
     <a href="#possible-implementation"><span class="secno">7</span> <span class="content">Possible implementation</span></a>
     <ol class="toc">
      <li><a href="#reference-implementation"><span class="secno">7.1</span> <span class="content">Reference implementation</span></a>
      <li><a href="#contemporary-implementations"><span class="secno">7.2</span> <span class="content">Other implementations</span></a>
     </ol>
    <li><a href="#proposed-wording"><span class="secno">8</span> <span class="content">Proposed wording</span></a>
    <li><a href="#acknowledgements"><span class="secno">9</span> <span class="content">Acknowledgements</span></a>
    <li>
     <a href="#references"><span class="secno"></span> <span class="content">References</span></a>
     <ol class="toc">
      <li><a href="#normative"><span class="secno"></span> <span class="content">Normative References</span></a>
      <li><a href="#informative"><span class="secno"></span> <span class="content">Informative References</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <h2 class="heading settled" data-level="1" id="revisions"><span class="secno">1. </span><span class="content">Revision history</span><a class="self-link" href="#revisions"></a></h2>
   <h3 class="heading settled" data-level="1.1" id="changes-since-r3"><span class="secno">1.1. </span><span class="content">Changes since R3</span><a class="self-link" href="#changes-since-r3"></a></h3>
   <p>The paper was seen by LEWG at Sofia 2025, with the following outcome:</p>
   <blockquote>
     <b>ACTION</b>: Ask SG6 to look at the paper
and bring up issues / design questions back to LEWG if exists. 
    <p><b>POLL</b>: Forward “P3104R4: Bit permutations” to LWG for C++29.</p>
    <table>
     <tbody>
      <tr>
       <th>SF
       <th>F
       <th>N
       <th>SA
       <th>SA
      <tr>
       <td>7
       <td>13
       <td>1
       <td>0
       <td>1
    </table>
   </blockquote>
   <p>The following changes were made in preparation for the paper to be seen by SG6 and LWG:</p>
   <ul>
    <li data-md>
     <p>Mention lack of SIMD support in <a href="#why-no-simd">§ 6.6 Why no SIMD support?</a></p>
    <li data-md>
     <p>Convert SVG images to equivalent MathML in <a href="#proposed-wording">§ 8 Proposed wording</a> (purely editorial change, for accessibility and aesthetics)</p>
    <li data-md>
     <p>Other minor editorial wording changes</p>
    <li data-md>
     <p>
      Fix typo in formula for <code class="highlight"><c- n>bit_repeat</c-></code> (
      <del>N</del>
      <ins>n</ins>
      ) in <a href="#proposed-wording">§ 8 Proposed wording</a>
     </p>
   </ul>
   <h3 class="heading settled" data-level="1.2" id="changes-since-r2"><span class="secno">1.2. </span><span class="content">Changes since R2</span><a class="self-link" href="#changes-since-r2"></a></h3>
   <ul>
    <li data-md>
     <p>Revise the proposed wording.</p>
    <li data-md>
     <p>Drop the <code class="highlight"><c- n>l</c-></code> variants of <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code>.</p>
   </ul>
   <h3 class="heading settled" data-level="1.3" id="changes-since-r1"><span class="secno">1.3. </span><span class="content">Changes since R1</span><a class="self-link" href="#changes-since-r1"></a></h3>
   <p>The paper has been seen in Tokyo by SG18 with positive reception,
except for the <code class="highlight"><c- o>*</c-><c- n>_bit_permutation</c-></code> functions.
These have been removed to strengthen consensus.</p>
   <h3 class="heading settled" data-level="1.4" id="changes-since-r0"><span class="secno">1.4. </span><span class="content">Changes since R0</span><a class="self-link" href="#changes-since-r0"></a></h3>
   <ul>
    <li data-md>
     <p>Expand <a href="#hardware-support">§ 4.3 Hardware support</a>, taking more instructions into account, including AVX-512.</p>
    <li data-md>
     <p>Minor editorial fixes.</p>
   </ul>
   <h2 class="heading settled" data-level="2" id="intro"><span class="secno">2. </span><span class="content">Introduction</span><a class="self-link" href="#intro"></a></h2>
   <p>The C++ bit manipulation library in <code class="highlight"><c- o>&lt;</c-><c- n>bit</c-><c- o>></c-></code> is an invaluable abstraction from hardware operations.
Functions like <code class="highlight"><c- n>countl_zero</c-></code> help the programmer avoid use of intrinsic functions or inline
assembly.</p>
   <p>However, there are still a few operations which are non-trivial to implement in software
and have widely available hardware support.
Therefore, I propose to expand the bit manipulation library
with multiple bit permutation functions described below.
Even without hardware support, these functions provide great utility and/or help the developer
write more expressive code.</p>
   <h2 class="heading settled" data-level="3" id="proposed-features"><span class="secno">3. </span><span class="content">Proposed features</span><a class="self-link" href="#proposed-features"></a></h2>
   <p>I propose to add the following functions to the bit manipulation library (<code class="highlight"><c- o>&lt;</c-><c- n>bit</c-><c- o>></c-></code>).</p>
   <p class="note" role="note"><span class="marker">Note:</span> All constraints are exposition-only.
      The function bodies contain a naive implementation that merely illustrates the behavior.</p>
   <p class="note" role="note"><span class="marker">Note:</span> See <a href="#hardware-support">§ 4.3 Hardware support</a> for the corresponding hardware instructions.</p>
   <h3 class="heading settled" data-level="3.1" id="intro-bit-reverse"><span class="secno">3.1. </span><span class="content"><code class="highlight"><c- n>bit_reverse</c-></code></span><a class="self-link" href="#intro-bit-reverse"></a></h3>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_reverse</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>)</c-> <c- k>noexcept</c->
<c- p>{</c->
    <c- n>T</c-> <c- n>result</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>for</c-> <c- p>(</c-><c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c-> <c- n>i</c-> <c- o>&lt;</c-> <c- n>numeric_limits</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>digits</c-><c- p>;</c-> <c- o>++</c-><c- n>i</c-><c- p>)</c-> <c- p>{</c->
        <c- n>result</c-> <c- o>&lt;&lt;=</c-> <c- mi>1</c-><c- p>;</c->
        <c- n>result</c-> <c- o>|=</c-> <c- n>x</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>;</c->
        <c- n>x</c-> <c- o>>>=</c-> <c- mi>1</c-><c- p>;</c->
    <c- p>}</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Reverses the bits of <code class="highlight"><c- n>x</c-></code> so that the least significant bit becomes the most significant.</p>
   <div class="example" id="example-349d65a5"><a class="self-link" href="#example-349d65a5"></a> <code class="highlight"><c- n>bit_reverse</c-><c- p>(</c-><c- b>uint32_t</c-><c- p>{</c-><c- mh>0x00001234</c-><c- p>})</c-></code> equals <code class="highlight"><c- mh>0x24c80000</c-></code>. </div>
   <h3 class="heading settled" data-level="3.2" id="intro-bit-repeat"><span class="secno">3.2. </span><span class="content"><code class="highlight"><c- n>bit_repeat</c-></code></span><a class="self-link" href="#intro-bit-repeat"></a></h3>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_repeat</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- b>int</c-> <c- n>length</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>(</c->false<c- p>)</c->
<c- p>{</c->
    <c- n>T</c-> <c- n>result</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>for</c-> <c- p>(</c-><c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c-> <c- n>i</c-> <c- o>&lt;</c-> <c- n>numeric_limits</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>digits</c-><c- p>;</c-> <c- o>++</c-><c- n>i</c-><c- p>)</c-> <c- p>{</c->
        <c- n>result</c-> <c- o>|=</c-> <c- p>((</c-><c- n>x</c-> <c- o>>></c-> <c- p>(</c-><c- n>i</c-> <c- o>%</c-> <c- n>length</c-><c- p>))</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>)</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-><c- p>;</c->
    <c- p>}</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>Repeats a pattern stored in the least significant <code class="highlight"><c- n>length</c-></code> bits of <code class="highlight"><c- n>x</c-></code>, as many times as fits into <code class="highlight"><c- n>x</c-></code>.</p>
   <div class="example" id="example-50c3301e"><a class="self-link" href="#example-50c3301e"></a> <code class="highlight"><c- n>bit_repeat</c-><c- p>(</c-><c- b>uint32_t</c-><c- p>{</c-><c- mh>0xc</c-><c- p>},</c-> <c- mi>4</c-><c- p>)</c-></code> equals <code class="highlight"><c- mh>0xcccccccc</c-></code>. </div>
   <h3 class="heading settled" data-level="3.3" id="intro-bit-compress"><span class="secno">3.3. </span><span class="content"><code class="highlight"><c- n>bit_compress</c-></code></span><a class="self-link" href="#intro-bit-compress"></a></h3>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c->
<c- p>{</c->
    <c- n>T</c-> <c- n>result</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>for</c-> <c- p>(</c-><c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>,</c-> <c- n>j</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c-> <c- n>i</c-> <c- o>&lt;</c-> <c- n>numeric_limits</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>digits</c-><c- p>;</c-> <c- o>++</c-><c- n>i</c-><c- p>)</c-> <c- p>{</c->
        <c- b>bool</c-> <c- n>mask_bit</c-> <c- o>=</c-> <c- p>(</c-><c- n>m</c-> <c- o>>></c-> <c- n>i</c-><c- p>)</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>;</c->
        <c- n>result</c-> <c- o>|=</c-> <c- p>(</c-><c- n>mask_bit</c-> <c- o>&amp;</c-> <c- p>(</c-><c- n>x</c-> <c- o>>></c-> <c- n>i</c-><c- p>))</c-> <c- o>&lt;&lt;</c-> <c- n>j</c-><c- p>;</c->
        <c- n>j</c-> <c- o>+=</c-> <c- n>mask_bit</c-><c- p>;</c->
    <c- p>}</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>For each one-bit in <code class="highlight"><c- n>m</c-></code>, the corresponding bit in <code class="highlight"><c- n>x</c-></code> is taken and packed
contiguously into the result, starting with the least significant result bit.</p>
   <div class="example" id="example-f693274c">
    <a class="self-link" href="#example-f693274c"></a> 
<pre class="language-cpp highlight"><c- b>uint32_t</c-> <c- n>x</c-> <c- o>=</c->          <c- d>/* ... */</c-><c- p>;</c->  <c- c1>// a b c d</c->
<c- b>uint32_t</c-> <c- n>m</c-> <c- o>=</c->             <c- mb>0b0101</c-><c- p>;</c->  <c- c1>// 0 1 0 1</c->
<c- b>uint32_t</c-> <c- n>z</c-> <c- o>=</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>m</c-><c- p>);</c->  <c- c1>// 0 0 b d</c->
</pre>
    <p>Notice that bits <code class="highlight"><c- n>a</c-></code> and <code class="highlight"><c- n>c</c-></code> in <code class="highlight"><c- n>x</c-></code> are ignored
because the corresponding bit in the "mask" <code class="highlight"><c- n>m</c-></code> is <code class="highlight"><c- mi>0</c-></code>.
The remaining bits <code class="highlight"><c- n>b</c-></code> and <code class="highlight"><c- n>d</c-></code> are tightly packed to the right.</p>
   </div>
   <h3 class="heading settled" data-level="3.4" id="intro-bit-expand"><span class="secno">3.4. </span><span class="content"><code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#intro-bit-expand"></a></h3>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c->
<c- p>{</c->
    <c- n>T</c-> <c- n>result</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c->
    <c- k>for</c-> <c- p>(</c-><c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>0</c-><c- p>,</c-> <c- n>j</c-> <c- o>=</c-> <c- mi>0</c-><c- p>;</c-> <c- n>i</c-> <c- o>&lt;</c-> <c- n>numeric_limits</c-><c- o>&lt;</c-><c- n>T</c-><c- o>>::</c-><c- n>digits</c-><c- p>;</c-> <c- o>++</c-><c- n>i</c-><c- p>)</c-> <c- p>{</c->
        <c- b>bool</c-> <c- n>mask_bit</c-> <c- o>=</c-> <c- p>(</c-><c- n>m</c-> <c- o>>></c-> <c- n>i</c-><c- p>)</c-> <c- o>&amp;</c-> <c- mi>1</c-><c- p>;</c->
        <c- n>result</c-> <c- o>|=</c-> <c- p>(</c-><c- n>mask_bit</c-> <c- o>&amp;</c-> <c- p>(</c-><c- n>x</c-> <c- o>>></c-> <c- n>j</c-><c- p>))</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-><c- p>;</c->
        <c- n>j</c-> <c- o>+=</c-> <c- n>mask_bit</c-><c- p>;</c->
    <c- p>}</c->
    <c- k>return</c-> <c- n>result</c-><c- p>;</c->
<c- p>}</c->
</pre>
   <p>For each one-bit in <code class="highlight"><c- n>m</c-></code>, a bit from <code class="highlight"><c- n>x</c-></code>, starting with the least significant bit
is taken and shifted into the corresponding position of the <code class="highlight"><c- n>m</c-></code> bit.</p>
   <div class="example" id="example-88eb343a">
    <a class="self-link" href="#example-88eb343a"></a> 
<pre class="language-cpp highlight"><c- b>uint32_t</c-> <c- n>x</c-> <c- o>=</c->        <c- d>/* ... */</c-><c- p>;</c->  <c- c1>// a b c d</c->
<c- b>uint32_t</c-> <c- n>m</c-> <c- o>=</c->           <c- mb>0b0101</c-><c- p>;</c->  <c- c1>// 0 1 0 1</c->
<c- b>uint32_t</c-> <c- n>z</c-> <c- o>=</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>m</c-><c- p>);</c->  <c- c1>// 0 c 0 d</c->
</pre>
    <p>Notice that the bits <code class="highlight"><c- n>a</c-></code> and <code class="highlight"><c- n>b</c-></code> in <code class="highlight"><c- n>x</c-></code> are ignored
because the "mask" <code class="highlight"><c- n>m</c-></code> only has two one-bits.
The remaining bits <code class="highlight"><c- n>c</c-></code> and <code class="highlight"><c- n>d</c-></code> are placed
where <code class="highlight"><c- n>m</c-></code> has a one-bit.</p>
   </div>
   <h2 class="heading settled" data-level="4" id="motivation-and-scope"><span class="secno">4. </span><span class="content">Motivation and scope</span><a class="self-link" href="#motivation-and-scope"></a></h2>
   <p>Bit-reversal, repetition, compression, and expansion
are fundamental operations that meet multiple criteria
which make them suitable for standardization:</p>
   <ol>
    <li data-md>
     <p>They are common and useful operations.</p>
    <li data-md>
     <p>They can be used to implement numerous other operations.</p>
    <li data-md>
     <p>At least on some architectures, they have direct hardware support.</p>
    <li data-md>
     <p>They are non-trivial to implement efficiently in software.</p>
    <li data-md>
     <p>For known masks, numerous optimization opportunities are available.</p>
   </ol>
   <h3 class="heading settled" data-level="4.1" id="applications"><span class="secno">4.1. </span><span class="content">Applications</span><a class="self-link" href="#applications"></a></h3>
   <h4 class="heading settled" data-level="4.1.1" id="applications-of-bit-reverse"><span class="secno">4.1.1. </span><span class="content">Applications of <code class="highlight"><c- n>bit_reverse</c-></code></span><a class="self-link" href="#applications-of-bit-reverse"></a></h4>
   <p>Bit-reversal is a common operation with uses in:</p>
   <ul>
    <li data-md>
     <p><strong>Cryptography</strong>: scrambling bits</p>
    <li data-md>
     <p><strong>Networking</strong>: as part of <a href="https://en.wikipedia.org/wiki/Cyclic_redundancy_check">cyclic redundancy check</a> computation</p>
    <li data-md>
     <p><strong>Graphics</strong>: mirroring of images with one bit per pixel</p>
    <li data-md>
     <p><strong>Random number generation</strong>: reversal can counteract low entropy of low-order bits
such as in the case of <a href="https://en.wikipedia.org/wiki/Linear_congruential_generator">linear congruential generators</a></p>
    <li data-md>
     <p><strong>Digital signal processing</strong>: for radix-2 <a href="https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm">Cooley-Tukey FFT algorithms</a></p>
    <li data-md>
     <p><strong>Code obfuscation</strong>: security by obscurity</p>
   </ul>
   <h4 class="heading settled" data-level="4.1.2" id="applications-of-bit-repeat"><span class="secno">4.1.2. </span><span class="content">Applications of <code class="highlight"><c- n>bit_repeat</c-></code></span><a class="self-link" href="#applications-of-bit-repeat"></a></h4>
   <p>The generation of recurring bit patterns is such a fundamental operation
that it’s hard to tie to any specific domain, but here are some use cases:</p>
   <ul>
    <li data-md>
     <p><strong>Debugging</strong>: using obvious recurring bit pattenrs like <code class="highlight"><c- mh>0xcccc</c-><c- p>...</c-></code> to identify "garbage memory"</p>
    <li data-md>
     <p><strong>Bit manipulation</strong>: generating alternating sequences of <code class="highlight"><c- mi>1</c-></code> and <code class="highlight"><c- mi>0</c-></code> for various algorithms</p>
    <li data-md>
     <p><strong>Eliminating integer divison</strong>: for <code class="highlight"><c- n>x</c-> <c- o>>></c-> <c- p>(</c-><c- n>i</c-> <c- o>%</c-> <c- n>N</c-><c- p>)</c-></code> with very small <code class="highlight"><c- n>N</c-></code>, <code class="highlight"><c- n>bit_repeat</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>N</c-><c- p>)</c-> <c- o>>></c-> <c- n>i</c-></code> can be used instead</p>
    <li data-md>
     <p><strong>Testing</strong>: recurring bit patterns can make for good test cases when implementing numerics</p>
    <li data-md>
     <p><strong>Error detection</strong>: known bit patterns can be introduced to spot failed transmission</p>
   </ul>
   <h4 class="heading settled" data-level="4.1.3" id="applications-of-bit-compress-and-bit-expand"><span class="secno">4.1.3. </span><span class="content">Applications of <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#applications-of-bit-compress-and-bit-expand"></a></h4>
   <p>Compression and expansion are also common, with uses in:</p>
   <ul>
    <li data-md>
     <p><strong>Space-filling curves</strong>: <a href="https://en.wikipedia.org/wiki/Z-order_curve">Morton/Z-Order</a> and <a href="https://en.wikipedia.org/wiki/Hilbert_curve">Hilbert curves</a></p>
    <li data-md>
     <p><strong>Input/output</strong>: especially for variable-length encodings, such as UTF-8 (<a href="#input-output">§ 4.2.3 UTF-8 decoding with bit_compress</a>)</p>
    <li data-md>
     <p><strong>Chess engines</strong>: for <a href="https://en.wikipedia.org/wiki/Bitboard">bitboards</a>; see <a data-link-type="biblio" href="#biblio-chessprogramming1" title="chessprogramming.org/BMI2, Applications">[ChessProgramming1]</a></p>
    <li data-md>
     <p><strong>Genomics</strong>: according to <a data-link-type="biblio" href="#biblio-arm1" title="Introduction to SVE2, Issue 02, Revision 02">[ARM1]</a></p>
   </ul>
   <p>A GitHub code search for <code class="highlight"><c- o>/</c-><c- p>(</c-><c- n>_pdep_u</c-><c- o>|</c-><c- n>_pext_u</c-><c- p>)(</c-><c- mi>32</c-><c- o>|</c-><c- mi>64</c-><c- p>)</c-><c- o>/</c-> <c- n>AND</c-> <c- n>language</c-><c- o>:</c-><c- n>c</c-><c- o>++</c-></code> reveals ~1300 files which use the intrinsic wrappers for the x86 instructions.</p>
   <h3 class="heading settled" data-level="4.2" id="use-cases"><span class="secno">4.2. </span><span class="content">Motivating examples</span><a class="self-link" href="#use-cases"></a></h3>
   <h4 class="heading settled" data-level="4.2.1" id="implementing-countr-zero"><span class="secno">4.2.1. </span><span class="content">Implementing <code class="highlight"><c- n>countr_zero</c-></code> with <code class="highlight"><c- n>bit_repeat</c-></code></span><a class="self-link" href="#implementing-countr-zero"></a></h4>
   <p><a data-link-type="biblio" href="#biblio-anderson1" title="Bit Twiddling Hacks">[Anderson1]</a> contains a vast amount of algorithms,
many of which involve masks of alternating <code class="highlight"><c- mi>0</c-></code>s and <code class="highlight"><c- mi>1</c-></code>s.</p>
   <p>When written as "magic numbers" in code,
these masks can make it quite hard to understand the overall pattern
and to generalize these algorithms. <code class="highlight"><c- n>bit_repeat</c-></code> allows one to be more expressive here:</p>
   <div class="example" id="example-459731b5">
    <a class="self-link" href="#example-459731b5"></a> 
<pre class="highlight"><c- b>unsigned</c-> <c- b>int</c-> <c- n>v</c-><c- p>;</c->      <c- c1>// 32-bit word input to count zero bits on right</c->
<c- b>unsigned</c-> <c- b>int</c-> <c- n>c</c-> <c- o>=</c-> <c- mi>32</c-><c- p>;</c-> <c- c1>// c will be the number of zero bits on the right</c->
<c- n>v</c-> <c- o>&amp;=</c-> <c- o>-</c-><c- n>v</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-><c- p>)</c-> <c- n>c</c-><c- o>--</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <del><c- mh>0x0000FFFF</c-></del> <ins><c- n>bit_repeat</c-><c- p>((</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- mi>16</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c-> <c- mi>32</c-><c- p>)</c-></ins><c- p>)</c-> <c- n>c</c-> <c- o>-=</c-> <c- mi>16</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <del><c- mh>0x00FF00FF</c-></del> <ins><c- n>bit_repeat</c-><c- p>(</c-> <c- p>(</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- mi>8</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c-> <c- mi>16</c-><c- p>)</c-></ins><c- p>)</c-> <c- n>c</c-> <c- o>-=</c->  <c- mi>8</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <del><c- mh>0x0F0F0F0F</c-></del> <ins><c- n>bit_repeat</c-><c- p>(</c-> <c- p>(</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- mi>4</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c->  <c- mi>8</c-><c- p>)</c-></ins><c- p>)</c-> <c- n>c</c-> <c- o>-=</c->  <c- mi>4</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <del><c- mh>0x33333333</c-></del> <ins><c- n>bit_repeat</c-><c- p>(</c-> <c- p>(</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- mi>2</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c->  <c- mi>4</c-><c- p>)</c-></ins><c- p>)</c-> <c- n>c</c-> <c- o>-=</c->  <c- mi>2</c-><c- p>;</c->
<c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <del><c- mh>0x55555555</c-></del> <ins><c- n>bit_repeat</c-><c- p>(</c-> <c- p>(</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- mi>1</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c->  <c- mi>2</c-><c- p>)</c-></ins><c- p>)</c-> <c- n>c</c-> <c- o>-=</c->  <c- mi>1</c-><c- p>;</c->
</pre>
    <p>It is now obvious how this can be expressed in a loop:</p>
<pre class="language-cpp highlight"><c- c1>// ...</c->
<c- k>for</c-> <c- p>(</c-><c- b>int</c-> <c- n>i</c-> <c- o>=</c-> <c- mi>16</c-><c- p>;</c-> <c- n>i</c-> <c- o>!=</c-> <c- mi>0</c-><c- p>;</c-> <c- n>i</c-> <c- o>/=</c-> <c- mi>2</c-><c- p>)</c-> <c- p>{</c->
    <c- b>unsigned</c-> <c- n>mask</c-> <c- o>=</c-> <c- n>bit_repeat</c-><c- p>((</c-><c- mi>1u</c-> <c- o>&lt;&lt;</c-> <c- n>i</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c-> <c- n>i</c-> <c- o>*</c-> <c- mi>2</c-><c- p>);</c->
    <c- k>if</c-> <c- p>(</c-><c- n>v</c-> <c- o>&amp;</c-> <c- n>mask</c-><c- p>)</c-> <c- n>c</c-> <c- o>-=</c-> <c- n>i</c-><c- p>;</c->
<c- p>}</c->
</pre>
   </div>
   <p><code class="highlight"><c- n>bit_repeat</c-></code> has been an invaluable asset in the implementation of the remaining functions
in this proposal (see <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a> for details).</p>
   <h4 class="heading settled" data-level="4.2.2" id="interleaving-bits"><span class="secno">4.2.2. </span><span class="content">Interleaving bits with <code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#interleaving-bits"></a></h4>
   <p>A common use case for expansion is interleaving bits.
This translates Cartesian coordinates to the index on a <a href="https://en.wikipedia.org/wiki/Z-order_curve">Z-order curve</a>.
Space filling curves are a popular technique in compression.</p>
   <div class="example" id="example-4d619ee1">
    <a class="self-link" href="#example-4d619ee1"></a> 
<pre class="language-cpp highlight"><c- b>unsigned</c-> <c- n>x</c-> <c- o>=</c-> <c- mi>3</c-><c- p>;</c-> <c- c1>// 0b011</c->
<c- b>unsigned</c-> <c- n>y</c-> <c- o>=</c-> <c- mi>5</c-><c- p>;</c-> <c- c1>// 0b101</c->
<c- k>const</c-> <c- k>auto</c-> <c- n>i</c-> <c- o>=</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>bit_repeat</c-><c- p>(</c-><c- mb>0b10u</c-><c- p>,</c-> <c- mi>2</c-><c- p>))</c-> <c- c1>// i = 0b01'10'11</c->
             <c- o>|</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>y</c-><c- p>,</c-> <c- n>bit_repeat</c-><c- p>(</c-><c- mb>0b01u</c-><c- p>,</c-> <c- mi>2</c-><c- p>));</c->
</pre>
   </div>
   <h4 class="heading settled" data-level="4.2.3" id="input-output"><span class="secno">4.2.3. </span><span class="content">UTF-8 decoding with <code class="highlight"><c- n>bit_compress</c-></code></span><a class="self-link" href="#input-output"></a></h4>
   <p><code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> are useful in various I/O-related applications.
They are particularly helpful for dealing with variable-length encodings,
where "data bits" are interrupted by bits which signal continuation of the data.</p>
   <div class="example" id="example-c08c22a6">
    <a class="self-link" href="#example-c08c22a6"></a> The following code reads 4 bytes from some source of UTF-8 data and returns the codepoint.
For the sake of simplicity, let’s ignore details like reaching the end of the file, or I/O errors. 
<pre class="language-cpp highlight"><c- b>uint_least32_t</c-> <c- n>x</c-> <c- o>=</c-> <c- n>load32_little_endian</c-><c- p>(</c-><c- n>utf8_data_pointer</c-><c- p>);</c->
<c- k>switch</c-> <c- p>(</c-><c- n>countl_one</c-><c- p>(</c-><c- b>uint8_t</c-><c- p>(</c-><c- n>x</c-><c- p>)))</c-> <c- p>{</c->
<c- k>case</c-> <c- mi>0</c-><c- p>:</c-> <c- k>return</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mb>0b01111111</c-><c- p>);</c->
<c- k>case</c-> <c- mi>1</c-><c- p>:</c-> <c- d>/* error */</c-><c- p>;</c->
<c- k>case</c-> <c- mi>2</c-><c- p>:</c-> <c- k>return</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mb>0b00111111'00011111</c-><c- p>);</c->
<c- k>case</c-> <c- mi>3</c-><c- p>:</c-> <c- k>return</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mb>0b00111111'00111111'00001111</c-><c- p>);</c->
<c- k>case</c-> <c- mi>4</c-><c- p>:</c-> <c- k>return</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mb>0b00111111'00111111'00111111'00000111</c-><c- p>);</c->
<c- p>}</c->
</pre>
   </div>
   <h4 class="heading settled" data-level="4.2.4" id="building-operations"><span class="secno">4.2.4. </span><span class="content">Other operations based on <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#building-operations"></a></h4>
   <p>Many operations can be built on top of <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code>.
However, direct hardware support is often needed for the proposed functions to efficiently
implement them.
Even without such support, they can be canonalized into a faster form.
The point is that <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> allow you to <em>express</em> these operations.</p>
   <div class="example" id="example-9297318b">
    <a class="self-link" href="#example-9297318b"></a> 
<pre class="language-cpp highlight"><c- c1>// x &amp; 0xf</c->
<c- n>bit_expand</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mh>0xf</c-><c- p>)</c->
<c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mh>0xf</c-><c- p>)</c->

<c- c1>// (x &amp; 0xf) &lt;&lt; 4</c->
<c- n>bit_expand</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mh>0xf0</c-><c- p>)</c->
<c- c1>// (x >> 4) &amp; 0xf</c->
<c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mh>0xf0</c-><c- p>)</c->

<c- c1>// Clear the least significant one-bit of x.</c->
<c- n>x</c-> <c- o>^=</c-> <c- n>bit_expand</c-><c- p>(</c-><c- mi>1</c-><c- p>,</c-> <c- n>x</c-><c- p>)</c->
<c- c1>// Clear the nth least significant one-bit of x.</c->
<c- n>x</c-> <c- o>^=</c-> <c- n>bit_expand</c-><c- p>(</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- n>n</c-><c- p>,</c-> <c- n>x</c-><c- p>)</c->
<c- c1>// Clear the n least significant one-bits of x.</c->
<c- n>x</c-> <c- o>^=</c-> <c- n>bit_expand</c-><c- p>((</c-><c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- n>n</c-><c- p>)</c-> <c- o>-</c-> <c- mi>1</c-><c- p>,</c-> <c- n>x</c-><c- p>)</c->

<c- c1>// (x >> n) &amp; 1</c->
<c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mi>1</c-> <c- o>&lt;&lt;</c-> <c- n>n</c-><c- p>)</c->
<c- c1>// Get the least significant bit of x.</c->
<c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>x</c-><c- p>)</c-> <c- o>&amp;</c-> <c- mi>1</c->
<c- c1>// Get the nth least significant bit of x.</c->
<c- p>(</c-><c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>x</c-><c- p>)</c-> <c- o>>></c-> <c- n>n</c-><c- p>)</c-> <c- o>&amp;</c-> <c- mi>1</c->

<c- c1>// popcount(x)</c->
<c- n>countr_one</c-><c- p>(</c-><c- n>bit_compress</c-><c- p>(</c-><c- mi>-1u</c-><c- p>,</c-> <c- n>x</c-><c- p>))</c->
<c- n>countr_one</c-><c- p>(</c-><c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- n>x</c-><c- p>))</c->
</pre>
   </div>
   <h3 class="heading settled" data-level="4.3" id="hardware-support"><span class="secno">4.3. </span><span class="content">Hardware support</span><a class="self-link" href="#hardware-support"></a></h3>
   <table>
    <tbody>
     <tr>
      <th>Operation
      <th>x86_64
      <th>ARM
      <th>RISC-V
     <tr>
      <td><code class="highlight"><c- n>bit_reverse</c-></code>
      <td><a href="https://www.felixcloutier.com/x86/vpshufbitqmb"><code class="highlight"><c- n>vpshufbitqmb</c-></code></a><sup>AVX512_BITALG</sup>, (<a href="https://www.felixcloutier.com/x86/bswap"><code class="highlight"><c- n>bswap</c-></code></a>)
      <td><a href="https://docsmirror.github.io/A64/2023-06/rbit_z_p_z.html"><code class="highlight"><c- n>rbit</c-></code></a><sup>SVE2</sup>
      <td><a href="https://github.com/riscv/riscv-bitmanip/"><code class="highlight"><c- n>rev8</c-></code></a><sup>Zbb</sup>+<a href="https://drive.google.com/file/d/1Thd010Eh2DqnhDHpDd3SM7Ame7KENkPw/view"><code class="highlight"><c- n>brev8</c-></code></a><sup>Zbkb</sup>,(<a href="https://github.com/riscv/riscv-bitmanip/"><code class="highlight"><c- n>rev8</c-></code></a><sup>Zbb</sup>)
     <tr>
      <td><code class="highlight"><c- n>bit_repeat</c-></code>
      <td><a href="https://www.felixcloutier.com/x86/vpshufbitqmb"><code class="highlight"><c- n>vpshufbitqmb</c-></code></a><sup>AVX512_BITALG</sup>
      <td>
      <td>
     <tr>
      <td><code class="highlight"><c- n>bit_compress</c-></code>
      <td><a href="https://www.felixcloutier.com/x86/pext"><code class="highlight"><c- n>pext</c-></code></a><sup>BMI2</sup>
      <td><a href="https://dougallj.github.io/asil/doc/bext_z_zz_64.html"><code class="highlight"><c- n>bext</c-></code></a><sup>SVE2</sup>
      <td>(<a href="https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#165-vector-compress-instruction"><code class="highlight"><c- n>vcompress</c-></code></a><sup>V</sup>)
     <tr>
      <td><code class="highlight"><c- n>bit_expand</c-></code>
      <td><a href="https://www.felixcloutier.com/x86/pdep"><code class="highlight"><c- n>pdep</c-></code></a><sup>BMI2</sup>
      <td><a href="https://dougallj.github.io/asil/doc/bdep_z_zz_64.html"><code class="highlight"><c- n>bdep</c-></code></a><sup>SVE2</sup>
      <td>(<a href="https://github.com/riscv/riscv-v-spec/blob/master/v-spec.adoc#1651-synthesizing-vdecompress"><code class="highlight"><c- n>viota</c-></code>+<code class="highlight"><c- n>vrgather</c-></code></a><sup>V</sup>)
   </table>
   <p>(Parenthesized) entries signal that the instruction does not directly implement the function,
but greatly assists in its implementation.</p>
   <p class="note" role="note"><span class="marker">Note:</span> The AVX-512 <code class="highlight"><c- n>vpshufbitqmb</c-></code> instruction can implement any bit permutation in the mathematical sense, and more.</p>
   <p class="note" role="note"><span class="marker">Note:</span> The RISC-V <code class="highlight"><c- n>brev8</c-></code> instruction can also be found under the name <code class="highlight"><c- n>rev</c-><c- p>.</c-><c- n>b</c-></code>.
      There appears to have been a name change in 2022.</p>
   <h4 class="heading settled" data-level="4.3.1" id="hardware-support-reverse"><span class="secno">4.3.1. </span><span class="content">Support for <code class="highlight"><c- n>bit_reverse</c-></code></span><a class="self-link" href="#hardware-support-reverse"></a></h4>
   <p>This operation is directly implemented in ARM through <code class="highlight"><c- n>rbit</c-></code>.</p>
   <p>Any architecture with support for <code class="highlight"><c- n>byteswap</c-></code> (such as x86 with <code class="highlight"><c- n>bswap</c-></code>)
also supports bit-reversal in part. <a data-link-type="biblio" href="#biblio-warren1" title="Hacker&apos;s Delight, 2nd Edition">[Warren1]</a> presents an O(log n) algorithm which operates by swapping lower and upper <code class="highlight"><c- n>N</c-> <c- o>/</c-> <c- mi>2</c-></code>, ..., <code class="highlight"><c- mi>16</c-></code>, <code class="highlight"><c- mi>8</c-></code>, <code class="highlight"><c- mi>4</c-></code>, <code class="highlight"><c- mi>2</c-></code>, and <code class="highlight"><c- mi>1</c-></code> bits in parallel.
Byte-swapping implements these individual swaps up to 8 bits, requiring only three more
parallel swaps in software:</p>
<pre class="language-cpp highlight"><c- c1>// assuming a byte is an octet of bits, and assuming the width of x is a power of two</c->
<c- n>x</c-> <c- o>=</c-> <c- n>byteswap</c-><c- p>(</c-><c- n>x</c-><c- p>);</c->
<c- n>x</c-> <c- o>=</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0x0F0F0F0F</c-><c- p>)</c-> <c- o>&lt;&lt;</c->  <c- mi>4</c-> <c- o>|</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0xF0F0F0F0</c-><c- p>)</c-> <c- o>>></c->  <c- mi>4</c-><c- p>;</c-> <c- c1>// ... quartets of bits</c->
<c- n>x</c-> <c- o>=</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0x33333333</c-><c- p>)</c-> <c- o>&lt;&lt;</c->  <c- mi>2</c-> <c- o>|</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0xCCCCCCCC</c-><c- p>)</c-> <c- o>>></c->  <c- mi>2</c-><c- p>;</c-> <c- c1>// ... pairs of bits</c->
<c- n>x</c-> <c- o>=</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0x55555555</c-><c- p>)</c-> <c- o>&lt;&lt;</c->  <c- mi>1</c-> <c- o>|</c-> <c- p>(</c-><c- n>x</c-> <c- o>&amp;</c-> <c- mh>0xAAAAAAAA</c-><c- p>)</c-> <c- o>>></c->  <c- mi>1</c-><c- p>;</c-> <c- c1>// ... individual bits</c->
</pre>
   <p>It is worth noting that clang provides a cross-platform family of intrinsics. <a href="https://clang.llvm.org/docs/LanguageExtensions.html#builtin-bitreverse"><code class="highlight"><c- n>__builtin_bitreverse</c-></code></a> uses byte-swapping or bit-reversal instructions if possible.</p>
   <p>Such an intrinsic has been requested from GCC users a number of times in <a data-link-type="biblio" href="#biblio-gnu1" title="Bug 50481 - builtin to reverse the bit order">[GNU1]</a>.</p>
   <h4 class="heading settled" data-level="4.3.2" id="hardware-support-bit-repeat"><span class="secno">4.3.2. </span><span class="content">Support for <code class="highlight"><c- n>bit_repeat</c-></code></span><a class="self-link" href="#hardware-support-bit-repeat"></a></h4>
   <p>Firstly, note that for the pattern length, there are only up to <code class="highlight"><c- n>N</c-></code> relevant cases,
where <code class="highlight"><c- n>N</c-></code> is the operand width in bits.
It is feasible to <code class="highlight"><c- k>switch</c-></code> between these cases, where the length is constant in each case.</p>
   <p>While the AVX-512 instruction <code class="highlight"><c- n>vpshufbitqmb</c-></code> can be used for <em>all</em> cases, this is not the ideal
solution for most cases.
For very low or very great lengths, a naive solution is sufficient (and even optimal),
where we simply use <code class="highlight"><c- o>&lt;&lt;</c-></code> and <code class="highlight"><c- o>|</c-></code> to duplicate the pattern.
What actually matters is how often the pattern is repeated, i.e. <code class="highlight"><c- n>N</c-> <c- o>/</c-> <c- n>length</c-></code>.</p>
   <p>Specific cases like <code class="highlight"><c- n>bit_repeat</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mi>8</c-><c- p>)</c-></code>, <code class="highlight"><c- n>bit_repeat</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mi>16</c-><c- p>)</c-></code> can be implemented using
permutation/duplication/gather/broadcast instructions.</p>
   <p>However, note that the primary use of <code class="highlight"><c- n>bit_repeat</c-></code> is to express repeating bit patterns without magic numbers,
i.e. to improve code quality.
Often, both the pattern and the length are known at compile-time, making hardware support less relevant.
Even without hardware support, the reference implementation <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a> requires only O(log N)
fundamental bitwise operations.</p>
   <h4 class="heading settled" data-level="4.3.3" id="hardware-support-compress-expand"><span class="secno">4.3.3. </span><span class="content">Support for <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#hardware-support-compress-expand"></a></h4>
   <p>Starting with Haswell (2013), Intel CPUs directly implement compression and expansion with
with <code class="highlight"><c- n>pext</c-></code> and <code class="highlight"><c- n>pdep</c-></code> respectively.
AMD CPUs starting with Zen 3 implement <code class="highlight"><c- n>pext</c-></code> and <code class="highlight"><c- n>pdep</c-></code> with 3 cycles
latency, like Intel.
Zen 2 and older implement <code class="highlight"><c- n>pext</c-></code>/<code class="highlight"><c- n>pdep</c-></code> in microcode, with 18 cycles latency.</p>
   <p>ARM also supports these operations directly with <code class="highlight"><c- n>bext</c-></code>, <code class="highlight"><c- n>bdep</c-></code>, and <code class="highlight"><c- n>bgrp</c-></code> in the SVE2 instruction set. <a data-link-type="biblio" href="#biblio-warren1" title="Hacker&apos;s Delight, 2nd Edition">[Warren1]</a> mentions other older architectures with direct support.</p>
   <p>Overall, only recent instruction set extensions offer this functionality directly.
However, when the mask is a constant, many different strategies for hardware acceleration open up.
For example</p>
   <ul>
    <li data-md>
     <p>interleaving bits can be assisted (though not fully implemented) using ARM <code class="highlight"><c- n>zip1</c-></code>/<code class="highlight"><c- n>zip2</c-></code></p>
    <li data-md>
     <p>other permutations can be assisted by ARM <code class="highlight"><c- n>tbl</c-></code> and <code class="highlight"><c- n>tbx</c-></code></p>
   </ul>
   <p>As <a data-link-type="biblio" href="#biblio-warren1" title="Hacker&apos;s Delight, 2nd Edition">[Warren1]</a> explains, the cost of computing <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> in software is
dramatically lower for a constant mask.
For specific known masks (such as a mask with a single one-bit), the cost is extremely low.</p>
   <p>All in all, there are multiple factors that strongly suggest a standard library implementation:</p>
   <ol>
    <li data-md>
     <p>The strategy for computing <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> depends greatly on the architecture
and on information about the mask, even if the exact mask isn’t known.</p>
     <ul>
      <li data-md>
       <p><code class="highlight"><c- n>tzcnt</c-></code>, <code class="highlight"><c- n>clmul</c-></code> (see <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a> or <a data-link-type="biblio" href="#biblio-zp7" title="Zach&apos;s Peppy Parallel-Prefix-Popcountin&apos; PEXT/PDEP Polyfill">[Zp7]</a> for specifics), and <code class="highlight"><c- n>popcnt</c-></code> are helpful.</p>
     </ul>
    <li data-md>
     <p>ISO C++ does not offer a mechanism through which all of this information can be utilized.
Namely, it is not possible to change strategy based on information that only becomes available
during optimization passes.
Compiler extensions such as <code class="highlight"><c- n>__builtin_constant_p</c-></code> offer a workaround.</p>
    <li data-md>
     <p>ISO C++ does not offer a mechanism through which function implementations can be chosen
based on the surrounding context.
In a situation where multiple <code class="highlight"><c- n>bit_compress</c-></code> calls with the same mask <code class="highlight"><c- n>m</c-></code> are performed,
it is significantly faster to pre-compute information based on the mask once,
and utilize it in subsequent calls.
The same technique can be used to accelerate integer division for multiple divisions with the
same divisor.</p>
   </ol>
   <p>Bullets 2. and 3. suggest that <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> benefit from being
implemented directly in the compiler via intrinsic,
even if hardware does not directly implement these operations.</p>
   <p>Even with a complete lack of hardware support, a software implementation of <code class="highlight"><c- n>compress_bitsr</c-></code> in <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a> emits essentially optimal code if the mask is known.</p>
   <div class="example" id="example-24d2a732">
    <a class="self-link" href="#example-24d2a732"></a> 
<pre class="language-cpp highlight"><c- b>unsigned</c-> <c- nf>bit_compress_known_mask</c-><c- p>(</c-><c- b>unsigned</c-> <c- n>x</c-><c- p>)</c-> <c- p>{</c->
    <c- k>return</c-> <c- n>cxx26bp</c-><c- o>::</c-><c- n>bit_compress</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mh>0xf0f0u</c-><c- p>);</c->
<c- p>}</c->
</pre>
    <p>Clang 18 emits the following (and GCC virtually the same); see <a data-link-type="biblio" href="#biblio-compilerexplorer1" title="Compiler Explorer example for bit_compress">[CompilerExplorer1]</a>:</p>
<pre class="language-asm highlight"><c- nf>bit_compress_known_mask</c-><c- p>(</c-><c- no>unsigned</c-> <c- no>int</c-><c- p>):</c-> <c- c1># bit_compress_known_mask(unsigned int edi)</c->
        <c- nf>mov</c->     <c- no>eax</c-><c- p>,</c-> <c- no>edi</c->               <c- c1># {   unsigned int eax = edi;</c->
        <c- nf>shr</c->     <c- no>eax</c-><c- p>,</c-> <c- mi>4</c->                 <c- c1>#     eax >>= 4;</c->
        <c- nf>and</c->     <c- no>eax</c-><c- p>,</c-> <c- mi>15</c->                <c- c1>#     eax &amp;= 0xf;</c->
        <c- nf>shr</c->     <c- no>edi</c-><c- p>,</c-> <c- mi>8</c->                 <c- c1>#     edi >>= 8;</c->
        <c- nf>and</c->     <c- no>edi</c-><c- p>,</c-> <c- mi>240</c->               <c- c1>#     edi &amp;= 0xf0;</c->
        <c- nf>or</c->      <c- no>eax</c-><c- p>,</c-> <c- no>edi</c->               <c- c1>#     eax |= edi;</c->
        <c- nf>ret</c->                            <c- c1>#     return eax; }</c->
</pre>
    <p>Knowing the implementation of <code class="highlight"><c- n>bit_compress</c-></code>, this feels like dark magic.
This is an optimizing compiler at its finest hour.</p>
   </div>
   <h2 class="heading settled" data-level="5" id="impact-on-existing-code"><span class="secno">5. </span><span class="content">Impact on existing code</span><a class="self-link" href="#impact-on-existing-code"></a></h2>
   <p>This proposal is purely a standard library expansion.
No existing code is affected.</p>
   <h2 class="heading settled" data-level="6" id="design"><span class="secno">6. </span><span class="content">Design considerations</span><a class="self-link" href="#design"></a></h2>
   <p>The design choices in this paper are based on <a data-link-type="biblio" href="#biblio-p0553r4" title="Bit operations">[P0553R4]</a>, wherever applicable.</p>
   <h3 class="heading settled" data-level="6.1" id="bit-repeat-signature"><span class="secno">6.1. </span><span class="content">Signature of <code class="highlight"><c- n>bit_repeat</c-></code></span><a class="self-link" href="#bit-repeat-signature"></a></h3>
   <p><code class="highlight"><c- n>bit_repeat</c-></code> follows the "use <code class="highlight"><c- b>int</c-></code> if possible" rule mentioned in <a data-link-type="biblio" href="#biblio-p0553r4" title="Bit operations">[P0553R4]</a>.
Other functions such as <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>rotl</c-></code> and <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>rotr</c-></code> also accept an <code class="highlight"><c- b>int</c-></code>.</p>
   <p>It is also the only function not marked <code class="highlight"><c- k>noexcept</c-></code>.
It does not throw, but it is not <code class="highlight"><c- k>noexcept</c-></code> due to its narrow contract (Lakos rule).</p>
   <h3 class="heading settled" data-level="6.2" id="naming-compress-expand"><span class="secno">6.2. </span><span class="content">Why the names <em>compress</em> and <em>expand</em>?</span><a class="self-link" href="#naming-compress-expand"></a></h3>
   <p>The use of <code class="highlight"><c- n>compress</c-></code> and <code class="highlight"><c- n>expand</c-></code> is consistent with the mask-based permutations for <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>simd</c-></code> proposed in <a data-link-type="biblio" href="#biblio-p2664r6" title="Extend std::simd with permutation API">[P2664R6]</a>.</p>
   <p>Furthermore, there are multiple synonymous sets of terminology:</p>
   <ol>
    <li data-md>
     <p><code class="highlight"><c- n>deposit</c-></code> and <code class="highlight"><c- n>extract</c-></code></p>
    <li data-md>
     <p><code class="highlight"><c- n>compress</c-></code> and <code class="highlight"><c- n>expand</c-></code></p>
    <li data-md>
     <p><code class="highlight"><c- n>gather</c-></code> and <code class="highlight"><c- n>scatter</c-></code></p>
   </ol>
   <p>I have decided against <code class="highlight"><c- n>deposit</c-></code> and <code class="highlight"><c- n>extract</c-></code> because of its ambiguity:</p>
   <p>Taking the input <code class="highlight"><c- mb>0b10101</c-></code> and densely packing it to <code class="highlight"><c- mb>0b111</c-></code> could be described as:</p>
   <blockquote>
    <p>Extract each second bit from <code class="highlight"><c- mb>0b10101</c-></code> and densely deposit it into the result.</p>
   </blockquote>
   <p>Similarly, taking the input <code class="highlight"><c- mb>0b111</c-></code> and expanding it into <code class="highlight"><c- mb>0b10101</c-></code> could be described as:</p>
   <blockquote>
    <p>Extract each bit from <code class="highlight"><c- mb>0b111</c-></code> and sparsely deposit it in the result.</p>
   </blockquote>
   <p>Both operations can be described with <code class="highlight"><c- n>extract</c-></code> and <code class="highlight"><c- n>deposit</c-></code> terminology,
making it virtually useless for keeping the operations apart. <code class="highlight"><c- n>gather</c-></code> and <code class="highlight"><c- n>scatter</c-></code> are simply the least common way to describe these operations, which makes <code class="highlight"><c- n>compress</c-></code> and <code class="highlight"><c- n>expand</c-></code> the best candidates.</p>
   <p>Further design choices are consistent with <a data-link-type="biblio" href="#biblio-p0553r4" title="Bit operations">[P0553R4]</a>.
The abbreviations <code class="highlight"><c- n>l</c-></code> and <code class="highlight"><c- n>r</c-></code> for left/right are consistent with <code class="highlight"><c- n>rotl</c-></code>/<code class="highlight"><c- n>rotr</c-></code>.
The prefix <code class="highlight"><c- n>bit_</c-></code> is consistent with <code class="highlight"><c- n>bit_floor</c-></code> and <code class="highlight"><c- n>bit_ceil</c-></code>.</p>
   <h3 class="heading settled" data-level="6.3" id="further-generalization"><span class="secno">6.3. </span><span class="content">Why the lack of generalization?</span><a class="self-link" href="#further-generalization"></a></h3>
   <h4 class="heading settled" data-level="6.3.1" id="generalized-compress-expand"><span class="secno">6.3.1. </span><span class="content">No generalized <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></span><a class="self-link" href="#generalized-compress-expand"></a></h4>
   <p><a data-link-type="biblio" href="#biblio-n3864" title="A constexpr bitwise operations library for C++">[N3864]</a> originally suggested much more general versions of compression and expansion,
which support:</p>
   <ol>
    <li data-md>
     <p>performing the operation not just on the whole operand, but on "words" of it, in parallel</p>
    <li data-md>
     <p>performing the operation not just on bits, but on arbitrarily sized groups of bits</p>
   </ol>
   <p><strong>I don’t propose this generality</strong> for the following reasons:</p>
   <ol>
    <li data-md>
     <p>The utility functions in <code class="highlight"><c- o>&lt;</c-><c- n>bit</c-><c- o>></c-></code> are not meant to provide a full bitwise manipulation library,
but fundamental operations, especially those that can be accelerated
in hardware while still having reasonable software fallbacks.</p>
    <li data-md>
     <p>These more general form can be built on top of the proposed hardware-oriented versions.
This can be done with relative ease and with little to no overhead.</p>
    <li data-md>
     <p>The generality falsely suggests hardware support for all forms, despite the function only being
accelerated for specific inputs.
This makes the performance characteristics unpredictable.</p>
    <li data-md>
     <p>The proposed functions have wide contracts and can be <code class="highlight"><c- k>noexcept</c-></code> (Lakos rule).
Adding additional parameters would likely require a narrow contract.</p>
    <li data-md>
     <p>Generality adds complexity to the standardization process, to implementation,
and from the perspective of language users.
It is unclear whether this added complexity is worth it in this case.</p>
   </ol>
   <h4 class="heading settled" data-level="6.3.2" id="generalized-bit-reverse"><span class="secno">6.3.2. </span><span class="content">No generalized <code class="highlight"><c- n>bit_reverse</c-></code></span><a class="self-link" href="#generalized-bit-reverse"></a></h4>
   <p>Bit reversal can also be generalized to work with any group size:</p>
<pre class="language-cpp highlight"><c- k>template</c-> <c- o>&lt;</c-><c- k>typename</c-> <c- nc>T</c-><c- o>></c->
<c- n>T</c-> <c- n>bit_reverse</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- b>int</c-> <c- n>group_size</c-> <c- o>=</c-> <c- mi>1</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>(</c->false<c- p>);</c->
</pre>
   <p>With this generalization, <code class="highlight"><c- n>byteswap</c-><c- p>(</c-><c- n>x</c-><c- p>)</c-></code> on conventional platforms
is equivalent to <code class="highlight"><c- n>bit_reverse</c-><c- p>(</c-><c- n>x</c-><c- p>,</c-> <c- mi>8</c-><c- p>)</c-></code>.</p>
   <p>However, this general version is much less used, not as consistently supported in
hardware, and has a narrow contract. <code class="highlight"><c- n>group_size</c-></code> must be a nonzero factor of <code class="highlight"><c- n>x</c-></code> for this operation to be meaningful.</p>
   <p>Therefore, a generalized bit-reversal is not proposed in this paper.</p>
   <h3 class="heading settled" data-level="6.4" id="unusual-signature"><span class="secno">6.4. </span><span class="content">Why does the signature of <code class="highlight"><c- n>bit_compress</c-></code> require two same <code class="highlight"><c- n>T</c-></code>s?</span><a class="self-link" href="#unusual-signature"></a></h3>
   <p>Initially, I went through a number of different signatures.</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- p>,</c-> <c- n>unsigned_integral</c-> <c- n>X</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>X</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
   <p>This signature is quite clever because the result never has more bits than the mask <code class="highlight"><c- n>m</c-></code>.
However, the the behavior is not immediately obvious when working zero-extension occurs,
especially when the mask has more one-bits than <code class="highlight"><c- n>x</c-></code> is wide.</p>
   <p>Since this proposal includes low-level bit operations, it is reasonable and safe to require
the user to be explicit.
A call to <code class="highlight"><c- n>bit_compress</c-></code> or <code class="highlight"><c- n>bit_expand</c-></code> with two different types is likely a design flaw or bug.
Therefore, I have settled on the very simple signature:</p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- n>unsigned_integral</c-> <c- n>T</c-><c- o>></c->
<c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
   <p class="note" role="note"><span class="marker">Note:</span> The proposal originally included a variant of <code class="highlight"><c- n>bit_compress</c-></code> which compresses
to the left (to the most significant bits),
and mixed widths would be even more complicated for that variant.</p>
   <h3 class="heading settled" data-level="6.5" id="no-left-compress-expand"><span class="secno">6.5. </span><span class="content">Why no left variant for <code class="highlight"><c- n>bit_compress</c-></code>?</span><a class="self-link" href="#no-left-compress-expand"></a></h3>
   <p>The paper originally had <code class="highlight"><c- n>bit_compressl</c-></code> and <code class="highlight"><c- n>bit_expandl</c-></code> counterparts which are biased
towards the most significant bits rather than the least significant bits.
These have been removed because</p>
   <ul>
    <li data-md>
     <p>they add clunkyness compared to just having one function,</p>
    <li data-md>
     <p><a data-link-type="biblio" href="#biblio-p2664r6" title="Extend std::simd with permutation API">[P2664R6]</a> doesn’t have left/right variants either, and we want symmetry with <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>simd</c-></code>,</p>
    <li data-md>
     <p>users will want the right-hand variants almost every time anyway, and</p>
    <li data-md>
     <p>only the right-hand variants have direct hardware support in the form of <code class="highlight"><c- n>pext</c-></code>, <code class="highlight"><c- n>pdep</c-></code> et al.</p>
   </ul>
   <h3 class="heading settled" data-level="6.6" id="why-no-simd"><span class="secno">6.6. </span><span class="content">Why no SIMD support?</span><a class="self-link" href="#why-no-simd"></a></h3>
   <p>Following <a data-link-type="biblio" href="#biblio-p2933r4" title="Extend <bit> header function with overloads for std::simd">[P2933R4]</a>,
almost all <code class="highlight"><c- o>&lt;</c-><c- n>bit</c-><c- o>></c-></code> functions also have SIMD overloads.
This means that the current design introduces inconsistency.</p>
   <p>However, R3 of this proposal is already design-approved by LEWG,
so to avoid holding up this paper’s progress based on <code class="highlight"><c- n>std</c-><c- o>::</c-><c- n>simd</c-></code> overloads,
those are proposed separately, in <a data-link-type="biblio" href="#biblio-p3772r0" title="std::simd overloads for bit permutations">[P3772R0]</a>.</p>
   <h2 class="heading settled" data-level="7" id="possible-implementation"><span class="secno">7. </span><span class="content">Possible implementation</span><a class="self-link" href="#possible-implementation"></a></h2>
   <h3 class="heading settled" data-level="7.1" id="reference-implementation"><span class="secno">7.1. </span><span class="content">Reference implementation</span><a class="self-link" href="#reference-implementation"></a></h3>
   <p>All proposed functions have been implemented in <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a>.
This reference implementation is compatible with all three major compilers,
and leverages hardware support from ARM and x86_64 where possible.</p>
   <h3 class="heading settled" data-level="7.2" id="contemporary-implementations"><span class="secno">7.2. </span><span class="content">Other implementations</span><a class="self-link" href="#contemporary-implementations"></a></h3>
   <p><a data-link-type="biblio" href="#biblio-warren1" title="Hacker&apos;s Delight, 2nd Edition">[Warren1]</a> presents algorithms which are the basis for <a data-link-type="biblio" href="#biblio-schultke1" title="C++26 Bit Permutations">[Schultke1]</a>.</p>
   <ul>
    <li data-md>
     <p>An O(log n) <code class="highlight"><c- n>bit_reverse</c-></code></p>
    <li data-md>
     <p>An O(log<sup>2</sup> n) <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code></p>
     <ul>
      <li data-md>
       <p>can be O(log n) with hardware support for
 carry-less multiplication aka. GF(2) polynomial multiplication</p>
     </ul>
   </ul>
   <p><a data-link-type="biblio" href="#biblio-zp7" title="Zach&apos;s Peppy Parallel-Prefix-Popcountin&apos; PEXT/PDEP Polyfill">[Zp7]</a> offers fast software implementations for <code class="highlight"><c- n>pext</c-></code> and <code class="highlight"><c- n>pdep</c-></code>, optimized for x86_64.</p>
   <p><a data-link-type="biblio" href="#biblio-stackoverflow1" title="What is a fast fallback algorithm which emulates PDEP and PEXT in software?">[StackOverflow1]</a> contains discussion of various possible software implementations
of <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code>.</p>
   <h2 class="heading settled" data-level="8" id="proposed-wording"><span class="secno">8. </span><span class="content">Proposed wording</span><a class="self-link" href="#proposed-wording"></a></h2>
   <p>The wording is relative to <a data-link-type="biblio" href="#biblio-n5008" title="Working Draft, Programming Languages — C++">[N5008]</a>.</p>
   <p>In subclause <a href="https://eel.is/c++draft/version.syn">[version.syn]</a>,
paragraph 2, update the synopsis as follows:</p>
   <blockquote>
<pre class="highlight"><code><c- cp>#define __cpp_lib_bitops                    </c-><del><c- cp>201907L</c-></del><ins><c- cp>20XXXXL</c-></ins><c- cp> </c-><c- c1>// freestanding, also in &lt;bit></c->
</code></pre>
   </blockquote>
   <p>In subclause <a href="https://eel.is/c++draft/bit.syn">[bit.syn]</a>,
update the synopsis as follows:</p>
   <blockquote>
<pre class="highlight"><code><c- p>[</c->…<c- p>]</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- b>int</c-> <c- n>popcount</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->

<ins><c- c1>// [bit.permute], permutations</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_reverse</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_repeat</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- b>int</c-> <c- n>l</c-><c- p>);</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
<c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c-></ins>

<c- c1>// [bit.endian], endian</c->
<c- p>[</c->…<c- p>]</c->
</code></pre>
   </blockquote>
   <p>In subclause <a href="https://eel.is/c++draft/bit">[bit]</a>,
add the following subclause after <a href="https://eel.is/c++draft/bit.count">[bit.count]</a>:</p>
   <div class="ins-block">
    <p class="subclause-title"> <span><strong>X.X.X Permutation</strong></span> <span><strong>[bit.permute]</strong></span> </p>
     <p-> 1 In the following descriptions, let <em>N</em> denote the value of <code class="highlight"><c- n>numeric_limits</c-><c- o>&lt;</c-><c- n>T</c-><c- o>></c->​<c- o>::</c->​<c- n>digits</c-></code>, and
    let <em>α</em><sub><em>n</em></sub> denote the value of the <em>n</em>-th least significant bit
    in the base-2 representation of an integer <em>α</em>, so that <em>α</em> equals <math display="inline"><mrow><mrow><munderover><mo movablelimits="true">∑</mo><mrow><mi>n</mi><mo>=</mo><mn>0</mn></mrow><mrow><mi>N</mi><mo>−</mo><mn>1</mn></mrow></munderover></mrow><mrow><msub><mi>α</mi><mi>n</mi></msub><msup><mn>2</mn><mi>n</mi></msup></mrow></mrow></math>. </p-> 
    <p><p-></p-></p>
<pre class="highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_reverse</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
    <p> <p- class="indent"> 2 <em>Constraints</em>: <code class="highlight"><c- n>T</c-></code> is an unsigned integer type ([basic.fundamental]). </p-> <p- class="indent"> 3 <em>Returns</em>: <span><math display="inline"><mrow><mi>reverse</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo form="postfix" stretchy="false">)</mo></mrow></math></span>,
    where <span><math display="inline"><mi>reverse</mi></math></span> is given by [FORMULA 1], and <span><math display="inline"><mi>x</mi></math></span> is <code class="highlight"><c- n>x</c-></code>. </p-></p>
    <div class="formula">
     <math display="block">
      <mrow>
       <mi>reverse</mi>
       <mo form="prefix" stretchy="false">(</mo>
       <mi>x</mi>
       <mo form="postfix" stretchy="false">)</mo>
       <mo>=</mo>
       <mrow>
        <munderover>
         <mo movablelimits="false">∑</mo>
         <mrow>
          <mi>n</mi>
          <mo>=</mo>
          <mn>0</mn>
         </mrow>
         <mrow>
          <mi>N</mi>
          <mo>−</mo>
          <mn>1</mn>
         </mrow>
        </munderover>
       </mrow>
       <mrow>
        <msub>
         <mi>x</mi>
         <mi>n</mi>
        </msub>
        <msup>
         <mn>2</mn>
         <mrow>
          <mi>N</mi>
          <mo>−</mo>
          <mi>n</mi>
          <mo>−</mo>
          <mn>1</mn>
         </mrow>
        </msup>
       </mrow>
      </mrow>
     </math>
      [FORMULA 1] 
    </div>
    <div class="indent"> [<em>Note</em>: <code class="highlight"><c- n>bit_reverse</c-><c- p>(</c-><c- n>bit_reverse</c-><c- p>(</c-><c- n>x</c-><c- p>))</c-></code> equals <code class="highlight"><c- n>x</c-></code>. — <em>end note</em>] </div>
    <p><p-></p-></p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_repeat</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- b>int</c-> <c- n>l</c-><c- p>);</c->
</pre>
    <p> <p- class="indent"> 4 <em>Constraints</em>: <code class="highlight"><c- n>T</c-></code> is an unsigned integer type ([basic.fundamental]). </p-> <p- class="indent"> 5 <em>Preconditions</em>: <code class="highlight"><c- n>l</c-></code> is greater than zero. </p-> <p- class="indent"> 6 <em>Returns</em>: <span><math display="inline"><mrow><mi>repeat</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>m</mi><mo form="postfix" stretchy="false">)</mo></mrow></math></span>,
    where <span><math display="inline"><mi>repeat</mi></math></span> is given by [FORMULA 2], <span><math display="inline"><mi>x</mi></math></span> is <code class="highlight"><c- n>x</c-></code>, and <span><math display="inline"><mi>l</mi></math></span> is <code class="highlight"><c- n>l</c-></code>. </p-> <p- class="indent"> 7 <em>Throws</em>: Nothing. </p-></p>
    <div class="formula">
     <math display="block">
      <mrow>
       <mi>repeat</mi>
       <mo form="prefix" stretchy="false">(</mo>
       <mi>x</mi>
       <mo separator="true">,</mo>
       <mi>l</mi>
       <mo form="postfix" stretchy="false">)</mo>
       <mo>=</mo>
       <mrow>
        <munderover>
         <mo movablelimits="false">∑</mo>
         <mrow>
          <mi>n</mi>
          <mo>=</mo>
          <mn>0</mn>
         </mrow>
         <mrow>
          <mi>N</mi>
          <mo>−</mo>
          <mn>1</mn>
         </mrow>
        </munderover>
       </mrow>
       <mrow>
        <msub>
         <mi>x</mi>
         <mrow>
          <mo form="prefix" lspace="0em" rspace="0em" stretchy="false">(</mo>
          <mi>n</mi>
          <mo></mo>
          <mspace width="0.6667em"></mspace>
          <mpadded lspace="0">
           <mi>mod</mi>
          </mpadded>
          <mspace width="0.1667em"></mspace>
          <mspace width="0.1667em"></mspace>
          <mi>l</mi>
          <mo form="postfix" lspace="0em" rspace="0em" stretchy="false">)</mo>
         </mrow>
        </msub>
        <msup>
         <mn>2</mn>
         <mi>n</mi>
        </msup>
       </mrow>
      </mrow>
     </math>
      [FORMULA 2] 
    </div>
    <p><p-></p-></p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_compress</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
    <p> <p- class="indent"> 8 <em>Constraints</em>: <code class="highlight"><c- n>T</c-></code> is an unsigned integer type ([basic.fundamental]). </p-> <p- class="indent"> 9 <em>Returns</em>: <span><math display="inline"><mrow><mi>compress</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>m</mi><mo form="postfix" stretchy="false">)</mo></mrow></math></span>,
    where <span><math display="inline"><mi>compress</mi></math></span> is given by [FORMULA 3], <span><math display="inline"><mi>x</mi></math></span> is <code class="highlight"><c- n>x</c-></code>, and <span><math display="inline"><mi>m</mi></math></span> is <code class="highlight"><c- n>m</c-></code>. </p-></p>
    <div class="formula">
     <math display="block">
      <mrow>
       <mi>compress</mi>
       <mo form="prefix" stretchy="false">(</mo>
       <mi>x</mi>
       <mo separator="true">,</mo>
       <mi>m</mi>
       <mo form="postfix" stretchy="false">)</mo>
       <mo>=</mo>
       <mrow>
        <munderover>
         <mo movablelimits="false">∑</mo>
         <mrow>
          <mi>n</mi>
          <mo>=</mo>
          <mn>0</mn>
         </mrow>
         <mrow>
          <mi>N</mi>
          <mo>−</mo>
          <mn>1</mn>
         </mrow>
        </munderover>
       </mrow>
       <mrow>
        <msub>
         <mi>m</mi>
         <mi>n</mi>
        </msub>
        <msub>
         <mi>x</mi>
         <mi>n</mi>
        </msub>
        <msup>
         <mn>2</mn>
         <mrow>
          <mo form="prefix" lspace="0em" rspace="0em" stretchy="false">(</mo>
          <msubsup>
           <mo movablelimits="false">∑</mo>
           <mrow>
            <mi>k</mi>
            <mo>=</mo>
            <mn>0</mn>
           </mrow>
           <mrow>
            <mi>n</mi>
            <mo>−</mo>
            <mn>1</mn>
           </mrow>
          </msubsup>
          <msub>
           <mi>m</mi>
           <mi>k</mi>
          </msub>
          <mo form="postfix" lspace="0em" rspace="0em" stretchy="false">)</mo>
         </mrow>
        </msup>
       </mrow>
      </mrow>
     </math>
      [FORMULA 3] 
    </div>
    <p><p-></p-></p>
<pre class="language-cpp highlight"><c- k>template</c-><c- o>&lt;</c-><c- k>class</c-> <c- nc>T</c-><c- o>></c->
  <c- k>constexpr</c-> <c- n>T</c-> <c- n>bit_expand</c-><c- p>(</c-><c- n>T</c-> <c- n>x</c-><c- p>,</c-> <c- n>T</c-> <c- n>m</c-><c- p>)</c-> <c- k>noexcept</c-><c- p>;</c->
</pre>
    <p> <p- class="indent"> 10 <em>Constraints</em>: <code class="highlight"><c- n>T</c-></code> is an unsigned integer type ([basic.fundamental]). </p-> <p- class="indent"> 11 <em>Returns</em>: <span><math display="inline"><mrow><mi>expand</mi><mo form="prefix" stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>m</mi><mo form="postfix" stretchy="false">)</mo></mrow></math></span>,
    where <span><math display="inline"><mi>expand</mi></math></span> is given by [FORMULA 4], <span><math display="inline"><mi>x</mi></math></span> is <code class="highlight"><c- n>x</c-></code>, and <span><math display="inline"><mi>m</mi></math></span> is <code class="highlight"><c- n>m</c-></code>. </p-></p>
    <div class="formula">
     <math display="block">
      <mrow>
       <mi>expand</mi>
       <mo form="prefix" stretchy="false">(</mo>
       <mi>x</mi>
       <mo separator="true">,</mo>
       <mi>m</mi>
       <mo form="postfix" stretchy="false">)</mo>
       <mo>=</mo>
       <mrow>
        <munderover>
         <mo movablelimits="false">∑</mo>
         <mrow>
          <mi>n</mi>
          <mo>=</mo>
          <mn>0</mn>
         </mrow>
         <mrow>
          <mi>N</mi>
          <mo>−</mo>
          <mn>1</mn>
         </mrow>
        </munderover>
       </mrow>
       <mrow>
        <msub>
         <mi>m</mi>
         <mi>n</mi>
        </msub>
        <msub>
         <mi>x</mi>
         <mrow>
          <mo form="prefix" lspace="0em" rspace="0em" stretchy="false">(</mo>
          <msubsup>
           <mo movablelimits="false">∑</mo>
           <mrow>
            <mi>k</mi>
            <mo>=</mo>
            <mn>0</mn>
           </mrow>
           <mrow>
            <mi>n</mi>
            <mo>−</mo>
            <mn>1</mn>
           </mrow>
          </msubsup>
          <msub>
           <mi>m</mi>
           <mi>k</mi>
          </msub>
          <mo form="postfix" lspace="0em" rspace="0em" stretchy="false">)</mo>
         </mrow>
        </msub>
        <msup>
         <mn>2</mn>
         <mi>n</mi>
        </msup>
       </mrow>
      </mrow>
     </math>
      [FORMULA 4] 
    </div>
   </div>
   <p>In the subclause above, substitute the symbolic placeholders [FORMULA <em>N</em>] for
formula numbers, in the style of subclause <a href="https://eel.is/c++draft/c.math">[c.math]</a>.</p>
   <p class="note" role="note"><span class="marker">Note:</span> I would have preferred a less mathematical approach to defining these functions.
      However, it is too difficult to precisely define <code class="highlight"><c- n>bit_compress</c-></code> and <code class="highlight"><c- n>bit_expand</c-></code> without
      visual aids, pseudo-code, or other crutches.</p>
   <h2 class="heading settled" data-level="9" id="acknowledgements"><span class="secno">9. </span><span class="content">Acknowledgements</span><a class="self-link" href="#acknowledgements"></a></h2>
   <p>I greatly appreciate the assistance of Stack Overflow users in assisting me with research for
this proposal. 
I especially thank Peter Cordes for his tireless and selfless dedication to sharing knowledge.</p>
   <p>I also thank various Discord users from <a href="https://discord.com/invite/tccpp">Together C &amp; C++</a> and <a href="https://www.includecpp.org/discord/">#include&lt;C++></a> who have reviewed drafts of
this proposal and shared their thoughts.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

  var sidebarMedia = window.matchMedia('screen and (min-width: 78em)');
  var autoToggle   = function(e){ toggleSidebar(e.matches) };
  if(sidebarMedia.addListener) {
    sidebarMedia.addListener(autoToggle);
  }

  function toggleSidebar(on) {
    if (on == undefined) {
      on = !document.body.classList.contains('toc-sidebar');
    }

    /* Don't scroll to compensate for the ToC if we're above it already. */
    var headY = 0;
    var head = document.querySelector('.head');
    if (head) {
      // terrible approx of "top of ToC"
      headY += head.offsetTop + head.offsetHeight;
    }
    var skipScroll = window.scrollY < headY;

    var toggle = document.getElementById('toc-toggle');
    var tocNav = document.getElementById('toc');
    if (on) {
      var tocHeight = tocNav.offsetHeight;
      document.body.classList.add('toc-sidebar');
      document.body.classList.remove('toc-inline');
      toggle.innerHTML = collapseSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, 0 - tocHeight);
      }
      tocNav.focus();
      sidebarMedia.addListener(autoToggle); // auto-collapse when out of room
    }
    else {
      document.body.classList.add('toc-inline');
      document.body.classList.remove('toc-sidebar');
      toggle.innerHTML = expandSidebarText;
      if (!skipScroll) {
        window.scrollBy(0, tocNav.offsetHeight);
      }
      if (toggle.matches(':hover')) {
        /* Unfocus button when not using keyboard navigation,
           because I don't know where else to send the focus. */
        toggle.blur();
      }
    }
  }

  function createSidebarToggle() {
    /* Create the sidebar toggle in JS; it shouldn't exist when JS is off. */
    var toggle = document.createElement('a');
      /* This should probably be a button, but appearance isn't standards-track.*/
    toggle.id = 'toc-toggle';
    toggle.class = 'toc-toggle';
    toggle.href = '#toc';
    toggle.innerHTML = collapseSidebarText;

    sidebarMedia.addListener(autoToggle);
    var toggler = function(e) {
      e.preventDefault();
      sidebarMedia.removeListener(autoToggle); // persist explicit off states
      toggleSidebar();
      return false;
    }
    toggle.addEventListener('click', toggler, false);


    /* Get <nav id=toc-nav>, or make it if we don't have one. */
    var tocNav = document.getElementById('toc-nav');
    if (!tocNav) {
      tocNav = document.createElement('p');
      tocNav.id = 'toc-nav';
      /* Prepend for better keyboard navigation */
      document.body.insertBefore(tocNav, document.body.firstChild);
    }
    /* While we're at it, make sure we have a Jump to Toc link. */
    var tocJump = document.getElementById('toc-jump');
    if (!tocJump) {
      tocJump = document.createElement('a');
      tocJump.id = 'toc-jump';
      tocJump.href = '#toc';
      tocJump.innerHTML = tocJumpText;
      tocNav.appendChild(tocJump);
    }

    tocNav.appendChild(toggle);
  }

  var toc = document.getElementById('toc');
  if (toc) {
    createSidebarToggle();
    toggleSidebar(sidebarMedia.matches);

    /* If the sidebar has been manually opened and is currently overlaying the text
       (window too small for the MQ to add the margin to body),
       then auto-close the sidebar once you click on something in there. */
    toc.addEventListener('click', function(e) {
      if(e.target.tagName.toLowerCase() == "a" && document.body.classList.contains('toc-sidebar') && !sidebarMedia.matches) {
        toggleSidebar(false);
      }
    }, false);
  }
  else {
    console.warn("Can't find Table of Contents. Please use <nav id='toc'> around the ToC.");
  }

  /* Wrap tables in case they overflow */
  var tables = document.querySelectorAll(':not(.overlarge) > table.data, :not(.overlarge) > table.index');
  var numTables = tables.length;
  for (var i = 0; i < numTables; i++) {
    var table = tables[i];
    var wrapper = document.createElement('div');
    wrapper.className = 'overlarge';
    table.parentNode.insertBefore(wrapper, table);
    wrapper.appendChild(table);
  }

})();
</script>
  <h2 class="no-num no-ref heading settled" id="references"><span class="content">References</span><a class="self-link" href="#references"></a></h2>
  <h3 class="no-num no-ref heading settled" id="normative"><span class="content">Normative References</span><a class="self-link" href="#normative"></a></h3>
  <dl>
   <dt id="biblio-n5008">[N5008]
   <dd>Thomas Köppe. <a href="https://wg21.link/n5008"><cite>Working Draft, Programming Languages — C++</cite></a>. 15 March 2025. URL: <a href="https://wg21.link/n5008">https://wg21.link/n5008</a>
  </dl>
  <h3 class="no-num no-ref heading settled" id="informative"><span class="content">Informative References</span><a class="self-link" href="#informative"></a></h3>
  <dl>
   <dt id="biblio-anderson1">[Anderson1]
   <dd>Sean Eron Anderson. <a href="https://graphics.stanford.edu/~seander/bithacks.html"><cite>Bit Twiddling Hacks</cite></a>. URL: <a href="https://graphics.stanford.edu/~seander/bithacks.html">https://graphics.stanford.edu/~seander/bithacks.html</a>
   <dt id="biblio-arm1">[ARM1]
   <dd>Arm Developer Community. <a href="https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/102340_0001_02_en_introduction-to-sve2.pdf?revision=b208e56b-6569-4ae2-b6f3-cd7d5d1ecac3"><cite>Introduction to SVE2, Issue 02, Revision 02</cite></a>. URL: <a href="https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/102340_0001_02_en_introduction-to-sve2.pdf?revision=b208e56b-6569-4ae2-b6f3-cd7d5d1ecac3">https://developer.arm.com/-/media/Arm%20Developer%20Community/PDF/102340_0001_02_en_introduction-to-sve2.pdf?revision=b208e56b-6569-4ae2-b6f3-cd7d5d1ecac3</a>
   <dt id="biblio-chessprogramming1">[ChessProgramming1]
   <dd>VA. <a href="https://www.chessprogramming.org/BMI2#Applications"><cite>chessprogramming.org/BMI2, Applications</cite></a>. URL: <a href="https://www.chessprogramming.org/BMI2#Applications">https://www.chessprogramming.org/BMI2#Applications</a>
   <dt id="biblio-compilerexplorer1">[CompilerExplorer1]
   <dd>Jan Schultke. <a href="https://godbolt.org/z/5dcTjE5x3"><cite>Compiler Explorer example for bit_compress</cite></a>. URL: <a href="https://godbolt.org/z/5dcTjE5x3">https://godbolt.org/z/5dcTjE5x3</a>
   <dt id="biblio-gnu1">[GNU1]
   <dd>Marc Glisse et al.. <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50481"><cite>Bug 50481 - builtin to reverse the bit order</cite></a>. URL: <a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50481">https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50481</a>
   <dt id="biblio-n3864">[N3864]
   <dd>Matthew Fioravante. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3864.html"><cite>A constexpr bitwise operations library for C++</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3864.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3864.html</a>
   <dt id="biblio-p0553r4">[P0553R4]
   <dd>Jens Maurer. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html"><cite>Bit operations</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0553r4.html</a>
   <dt id="biblio-p2664r6">[P2664R6]
   <dd>Daniel Towner; Ruslan Arutyunyan. <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2664r6.html#permute_by_mask"><cite>Extend std::simd with permutation API</cite></a>. URL: <a href="https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2664r6.html#permute_by_mask">https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p2664r6.html#permute_by_mask</a>
   <dt id="biblio-p2933r4">[P2933R4]
   <dd>Daniel Towner, Ruslan Arutyunyan. <a href="https://wg21.link/p2933r4"><cite>Extend &lt;bit> header function with overloads for std::simd</cite></a>. 17 February 2025. URL: <a href="https://wg21.link/p2933r4">https://wg21.link/p2933r4</a>
   <dt id="biblio-p3772r0">[P3772R0]
   <dd>Jan Schultke. <a href="https://isocpp.org/files/papers/P3772R0.html"><cite>std::simd overloads for bit permutations</cite></a>. URL: <a href="https://isocpp.org/files/papers/P3772R0.html">https://isocpp.org/files/papers/P3772R0.html</a>
   <dt id="biblio-schultke1">[Schultke1]
   <dd>Jan Schultke. <a href="https://github.com/Eisenwave/cxx26-bit-permutations"><cite>C++26 Bit Permutations</cite></a>. URL: <a href="https://github.com/Eisenwave/cxx26-bit-permutations">https://github.com/Eisenwave/cxx26-bit-permutations</a>
   <dt id="biblio-stackoverflow1">[StackOverflow1]
   <dd>Jan Schultke et al.. <a href="https://stackoverflow.com/q/77834169/5740428"><cite>What is a fast fallback algorithm which emulates PDEP and PEXT in software?</cite></a>. URL: <a href="https://stackoverflow.com/q/77834169/5740428">https://stackoverflow.com/q/77834169/5740428</a>
   <dt id="biblio-warren1">[Warren1]
   <dd>Henry S. Warren, Jr.. <cite>Hacker's Delight, 2nd Edition</cite>. 
   <dt id="biblio-zp7">[Zp7]
   <dd>Zach Wegner. <a href="https://github.com/zwegner/zp7"><cite>Zach's Peppy Parallel-Prefix-Popcountin' PEXT/PDEP Polyfill</cite></a>. URL: <a href="https://github.com/zwegner/zp7">https://github.com/zwegner/zp7</a>
  </dl>