<!DOCTYPE html>
<html class=" xenmeeo idc0_340" lang="en">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
    <title>P2596R0: Improve std::hive::reshape</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 ***************************************************************/


/******************************************************************************/
/*                                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;
		}
		#toc .content:hover,
		#toc .content:focus {
			background: rgba(75%, 75%, 75%, .25);
			background: var(--a-hover-bg);
			border-bottom: 3px solid #054572;
			border-bottom: 3px solid var(--toclink-underline);
			margin-bottom: -3px;
		}
		#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 511ccb7, updated Mon Jun 6 13:31:59 2022 -0700"

      name="generator">
    <link href="https://isocpp.org/favicon.ico" rel="icon">
    <style>
ins  {background-color: #CCFFCC; text-decoration: underline;}
del  {background-color: #FFCACA; text-decoration: line-through;}
</style> <style>/* 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;
}</style>
    <style>/* 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;
}</style>
    <style>/* 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>/* style-issues */

a[href].issue-return {
    float: right;
    float: inline-end;
    color: var(--issueheading-text);
    font-weight: bold;
    text-decoration: none;
}
</style> <style>/* 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>/* 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%;
}
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>/* 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 */
</style> <style>/* style-darkmode */

@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; }
}
@media (prefers-color-scheme: dark) {
    :root {
        --selflink-text: black;
        --selflink-bg: silver;
        --selflink-hover-text: white;
    }
}

@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> </head>
  <body class="h-entry toc-sidebar">
    <div class="head">
      <p data-fill-with="logo"></p>
      <h1 class="p-name no-ref" id="title">P2596R0 critique</h1>
		<p>28-04-2023</p>
		<p>Audience: LEWG, SG14, WG21</p>
<p>Document number: P2857R0<br>
<p>Reply-to: Matthew Bentley &lt;mattreecebentley@gmail.com&gt;</p>

      <p>I have been asked to provide a textual form of the issues with Arthur O'Dwyer's paper. This is it. The critique follows Arthur's paper, crosses out the sections which are false, and annotates with my comments in red and in blue.</p>


      <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>P0447R20 <code class="highlight"><c- n="">std</c-><c- o="">::</c-><c-

            n="">hive</c-></code> proposes a complicated capacity model
        involving the library identifiers <code class="highlight"><c- n="">hive_limits</c-></code>,
        <code class="highlight"><c- n="">block_capacity_limits</c-></code>, <code

          class="highlight"><c- n="">block_capacity_hard_limits</c-></code>, <code

          class="highlight"><c- n="">reshape</c-></code>, in addition to <code

          class="highlight"><c- n="">capacity</c-></code>, <code class="highlight"><c-

            n="">reserve</c-></code>, <code class="highlight"><c- n="">shrink_to_fit</c-></code>,
        and <code class="highlight"><c- n="">trim_capacity</c-></code>.
        P0447R20’s model permits the user to specify a max block size<del>; this
          causes "secret quadratic behavior" on some common operations.</del>
        P0447R20’s model requires the container to track its min and max block
        sizes as part of its <del>(non-salient)</del> state.</p>
      <p>We propose a simpler model that involves the library identifiers <code

          class="highlight"><c- n="">max_block_size</c-></code> and <code class="highlight"><c-

            n="">reshape</c-></code>, in addition to <code class="highlight"><c-

            n="">capacity</c-></code>, <code class="highlight"><c- n="">reserve</c-></code>,
        <code class="highlight"><c- n="">shrink_to_fit</c-></code>, and <code class="highlight"><c-

            n="">trim_capacity</c-></code>. This model does not permit the user
        to specify a max block size<del>, so "secret quadratic behavior" is less
          common</del>. This model does not require the container to track
        anything; the new `reshape` is a simple mutating operation analogous to
        `reserve` or `sort`.\</p>
      <p style="color: red"><b>Matt: The user-defined block capacities are relevant to both performance and memory usage in hive. I would include them along with the O(1) skipping mechanism and erasure location recording mechanism as salient features, in that respect. This is explained in the paper, which Arthur has otherwise
          taken great pains to read. The various ways in which they are beneficial are explained in the summary at the bottom of this document.</b></p>
      <p style="color: red"><b>There is no secret quadratic behaviour in the container
          implementation and never has been. The so-called behaviour was (and no
          longer is) O(n) in the number of blocks, when an erasure causes a block to
          become empty of elements, but this behaviour no longer exists in the
          implementation, which was true at the time I received this paper. Further, Arthur's suggested alternative would not have removed this behaviour, as it relates primarily to block numbering, not how many blocks exist. The only it did was prevent the user from increasing the number of blocks.</b>
			 </p>
    </div>
      <h2 class="heading settled" data-level="2" id="intro"><span class="secno">2.
          </span><span class="content">Introduction: P0447R20’s model</span><a class="self-link"

          href="#intro"></a></h2>
      <p>P0447R20 <code class="highlight"><c- n="">hive</c-></code> is a
        bidirectional container<del>, basically a "rope with holes."</del>
        Compare it to the existing STL sequen-ce containers:</p>
      <p style="color: red; font-weight: bold">Matt: Arthur has done a lot of work testing the implementation
          and knows the structure to be linked list of blocks (although this is not the
          only way of implementing it). A rope is a binary tree of
          substrings. A hive cannot be implemented in this way. They are entirely dissimilar containers. This appears to be an attempt to create FUD.<span class="content"><br>
            <br>
</p>
      <p></p>
      <p><br>
      </p>
      <ul>
        <li data-md="">
          <p><code class="highlight"><c- n="">vector</c-></code> is a single
            block with spare capacity only on the end. Only one block ever
            exists at a time.</p>
        </li>
        <li data-md="">
          <p><code class="highlight"><c- n="">list</c-></code> is a linked list
            of equal-sized blocks, each with capacity 1; unused blocks are
            immediately deallocated.</p>
        </li>
        <li data-md="">
          <p><code class="highlight"><c- n="">deque</c-></code> is a vector of
            equal-sized blocks, each with capacity N; spare capacity exists at
            the end of the last block <em>and</em> at the beginning of the
            first block, but nowhere else.</p>
        </li>
        <li data-md="">
          <p><code class="highlight"><c- n="">hive</c-></code> is a linked list
            of variably-sized blocks; spare capacity ("holes") can appear
            anywhere in any block, and the container keeps track of where the
            "holes" are.</p>
        </li>
      </ul>
      <p>The blocks of a <code class="highlight"><c- n="">hive</c-></code> are
        variably sized. The intent is that as you insert into a hive, it will
        allocate new blocks of progressively larger sizes — just like <code class="highlight"><c-

            n="">vector</c-></code>'s geometric resizing, but without relocating
        any existing elements. This improves cache locality when iterating.</p>
      <p>We can represent a vector, list, or hive diagrammatically, using <code

          class="highlight"><c- p="">[</c-><c- n="">square</c-> <c- n="">brackets</c-><c-

            p="">]</c-></code> to bracket the elements belonging to a single
        block, and <code class="highlight"><c- n="">_</c-></code> to represent
        spare capacity ("holes"). There’s a lot of bookkeeping detail not
        captured by this representation; that’s okay for our purposes.</p>
      <pre class="highlight"><c- n="">std</c-><c- o="">::</c-><c- n="">vector</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c- n="">v</c-> <c- o="">=</c-> <c-

p="">{</c-><c- mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c-

p="">,</c-><c- mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c-

p="">};</c-> <c- c1="">// [1 2 3 4 5 6 _ _]</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">list</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c->   <c- n="">l</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">};</c-> <c- c1="">// [1] [2] [3] [4] [5] [6]</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c->   <c- n="">h</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">};</c-> <c- c1="">// [1 2 3 4 5 6]</c->
</pre>
      <p>Erasing from a vector shifts the later elements down. Erasing from a
        list or hive never needs to shift elements.</p>
      <pre class="highlight"><c- n="">v</c-><c- p="">.</c-><c- n="">erase</c-><c-

p="">(</c-><c- n="">std</c-><c- o="">::</c-><c- n="">next</c-><c- p="">(</c-><c-

n="">v</c-><c- p="">.</c-><c- n="">begin</c-><c- p="">()));</c->  <c- c1="">// [1 3 4 5 6 _ _ _]</c->
<c- n="">l</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">next</c-><c- p="">(</c-><c- n="">l</c-><c- p="">.</c-><c- n="">begin</c-><c-

p="">()));</c->  <c- c1="">// [1] [3] [4] [5] [6]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">next</c-><c- p="">(</c-><c- n="">h</c-><c- p="">.</c-><c- n="">begin</c-><c-

p="">()));</c->  <c- c1="">// [1 _ 3 4 5 6]</c->
</pre>
      <p>Reserving in a vector may invalidate iterators, because there’s no way
        to strictly "add" capacity. Reserving in a hive never invalidates
        iterators (except for <code class="highlight"><c- n="">end</c-><c- p="">()</c-></code>),
        because we can just add new blocks right onto the back of the container.
        (In practice, <code class="highlight"><c- n="">hive</c-></code> tracks
        unused blocks in a separate list so that iteration doesn’t have to
        traverse them; this diagrammatic representation doesn’t capture that
        detail.)</p>
      <pre class="highlight"><c- n="">v</c-><c- p="">.</c-><c- n="">reserve</c-><c-

p="">(</c-><c- mi="">10</c-><c- p="">);</c->  <c- c1="">// [1 3 4 5 6 _ _ _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">10</c-><c-

p="">);</c->  <c- c1="">// [1 _ 3 4 5 6] [_ _ _ _]</c->
</pre>
      <p>P0447R20 allows the programmer to specify <code class="highlight"><c-

            n="">min</c-></code> and <code class="highlight"><c- n="">max</c-></code>
        block capacities, via the <code class="highlight"><c- n="">std</c-><c-

            o="">::</c-><c- n="">hive_limits</c-></code> mechanism. No block in
        the hive is ever permitted to be smaller than <code class="highlight"><c-

            n="">min</c-></code> elements in capacity, nor greater than <code class="highlight"><c-

            n="">max</c-></code> elements in capacity. For example, we can
        construct a hive in which no block’s capacity will ever be smaller than
        4 or greater than 5.</p>
      <pre class="highlight"><c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c- n="">h</c-><c- p="">({</c-><c-

mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c-

mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">},</c-> <c-

n="">std</c-><c- o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">4</c-><c-

p="">,</c-> <c- mi="">5</c-><c- p="">));</c->
               <c- c1="">// [1 2 3 4 5] [6 _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">10</c-><c-

p="">);</c-> <c- c1="">// [1 2 3 4 5] [6 _ _ _] [_ _ _ _]</c->
</pre>
      <p>A hive can also be "reshaped" on the fly, after construction. In the
        following example, after creating a hive with one size-5 block, we <code

          class="highlight"><c- n="">reshape</c-></code> the hive to include
        only blocks of sizes between 3 and 4 inclusive. This means that the
        size-5 block is now "illegal"; its elements are redistributed to other
        blocks, and then it is deallocated, because this hive is no longer
        allowed to hold blocks of that size.</p>
      <pre class="highlight"><c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c- n="">h</c-><c- p="">({</c-><c-

mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c-

mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">},</c-> <c-

n="">std</c-><c- o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">4</c-><c-

p="">,</c-> <c- mi="">5</c-><c- p="">));</c->
               <c- c1="">// [1 2 3 4 5] [6 _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">10</c-><c-

p="">);</c-> <c- c1="">// [1 2 3 4 5] [6 _ _ _] [_ _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">3</c-><c- p="">,</c-> <c-

mi="">4</c-><c- p="">));</c->
               <c- c1="">// [6 1 2 3] [4 5 _ _]</c->
</pre>
      <p>Notice that <code class="highlight"><c- n="">reshape</c-></code>
        invalidates iterators (to element <code class="highlight"><c- mi="">1</c-></code>,
        for example), and can also undo the effects of <code class="highlight"><c-

            n="">reserve</c-></code> by reducing the overall capacity of the
        hive. (Before the reshape operation, <code class="highlight"><c- n="">h</c-><c-

            p="">.</c-><c- n="">capacity</c-><c- p="">()</c-></code> was 13;
        afterward it is only 8.) Programmers are advised to "<code class="highlight"><c-

            n="">reshape</c-></code> first, <code class="highlight"><c- n="">reserve</c-></code>
        second."</p>
      <h2 class="heading settled" data-level="3" id="motivation"><span class="secno">3.
          </span><span class="content">Criticisms of P0447R20’s model</span><a class="self-link"

          href="#motivation"></a></h2>
      <h3 class="heading settled" data-level="3.1" id="motivation-useless"><span

          style="text-decoration: line-through;"><span class="secno">3.1. </span><span

            class="content">Max block size is not useful in practice</span></span></h3>
      <p>One of the primary motivations for <code class="highlight"><c- n="">hive</c-></code>
        is to be usable in embedded/low-latency situations, where the programmer
        might want fine control over the memory allocation scheme. So at first
        glance it makes sense that the programmer should be able to specify min
        and max block capacities via <code class="highlight"><c- n="">hive_limits</c-></code>.
        However:</p>
      <ul>
        <li data-md="">
          <p><del>A programmer is likely
              to care about <em>min</em> block capacity (for cache locality),
              but not so much <em>max</em> capacity. The more contiguity the
              better! Why would I want to put a cap on it?<br>
              <br>
            </del>
			</p>
			<p style="color: red">
			<strong>Matt: Arthur has been given several
              reasons why max capacity is important in the reflector and on the
              github issues section for the reference implementation. In
              addition many have been included in the FAQ of the present paper,
              and in the publicly-available drafts of that paper, and some were
              included in the previous version of this paper (19), which
              evidently he has read as is reflected in the reflector
              discussions. These arguments and others are summarised in blue at the bottom of this paper. He has not provided any rebuttal for those reasons on
              the reflector or github, and none are referenced or rebutted here.<br>
              <a href="https://github.com/mattreecebentley/plf_hive/issues/22">https://github.com/mattreecebentley/plf_hive/issues/22</a><br>
              <a href="https://isocpp.org/files/papers/P0447R20.html#faq">https://isocpp.org/files/papers/P0447R20.html#faq</a>, items 11 &amp;
              12<br>
              <a href="https://isocpp.org/files/papers/P0447R19.html#faq">https://isocpp.org/files/papers/P0447R19.html#faq</a>, item 6<br>
              See: Lewg reflector, 4/05/2022, 1:42 pm, My reply Re: [isocpp-lib-ext]
              Notes on P0047R20, beginning with "On 29/04/2022 3:49 am, Arthur
              O'Dwyer wrote:" (<a href="https://lists.isocpp.org/lib-ext/2022/05/23129.php">https://lists.isocpp.org/lib-ext/2022/05/23129.php</a>).<br>
              <br>
</strong></p>
        </li>
        <li data-md="">
          <p>If the embedded programmer cares about max capacity, it’s likely
            because they’re using a slab allocator that hands out blocks of some
            fixed size (say, 1024 bytes).</p>
               <p style="color: red">
                <strong><br>
                  Matt: They will also be interested in memory waste based on their erasure and insertion patterns and performance. See summary.</strong></p>

				<p>But that doesn’t correspond to <code

              class="highlight"><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">0</c-><c-

                p="">,</c-> <c- mi="">1024</c-><c- p="">)</c-></code>. The min
            and max values in <code class="highlight"><c- n="">hive_limits</c-></code>
            are <em>counts of elements</em>, not the size of the actual
            allocation. So you might try dividing by <code class="highlight"><c-

                k="">sizeof</c-><c- p="">(</c-><c- n="">T</c-><c- p="">)</c-></code>;
            but that still won’t help, for two reasons:</p>
          <ul>
            <li data-md="">
              <p>Just like with <code class="highlight"><c- n="">std</c-><c- o="">::</c-><c-

                    n="">set</c-></code>, the size of the allocation is not the
                same as <code class="highlight"><c- k="">sizeof</c-><c- p="">(</c-><c-

                    n="">T</c-><c- p="">)</c-></code>. In the reference
                implementation, a block with capacity <code class="highlight"><c-

                    n="">n</c-></code> typically asks the allocator for <code class="highlight"><c-

                    n="">n</c-><c- o="">*</c-><c- k="">sizeof</c-><c- p="">(</c-><c-

                    n="">T</c-><c- p="">)</c-> <c- o="">+</c-> <c- n="">n</c->
                  <c- o="">+</c-> <c- mi="">1</c-></code> bytes of storage, to
                account for the skipfield structure. In my own implementation, I
                do a <code class="highlight"><c- n="">make_shared</c-></code>-like
optimization
                that asks the allocator for <code class="highlight"><c- k="">sizeof</c-><c-

                    p="">(</c-><c- n="">GroupHeader</c-><c- p="">)</c-> <c- o="">+</c->
                  <c- n="">n</c-><c- o="">*</c-><c- k="">sizeof</c-><c- p="">(</c-><c-

                    n="">T</c-><c- p="">)</c-> <c- o="">+</c-> <c- n="">n</c->
                  <c- o="">+</c-> <c- mi="">1</c-></code> bytes.<br>
               </p>
               <p style="color: red">
                <strong><br>
                  Matt: This is easy to work around via a static member
                  function, and one such has been provided in the most recent
                  versions of plf::colony for exactly this purpose ("max_elements_per_allocation", 6 lines of actual code). However I
                  think it an edge-case for a standard library implementation,
                  and possibly not worth including in std::hive? Open to suggestion.</strong></p>
            </li>
            <li data-md="">
              <p><del>The reference
                  implementation doesn’t store <code class="highlight"><c- n="">T</c-></code>
                  objects contiguously, when <code class="highlight"><c- n="">T</c-></code>
                  is small. When <code class="highlight"><c- n="">plf</c-><c- o="">::</c-><c-

                      n="">hive</c-><c- o="">&lt;</c-><c- b="">char</c-><c- o="">&gt;</c-></code>
                  allocates a block of capacity <code class="highlight"><c- n="">n</c-></code>,
                  it actually asks for <code class="highlight"><c- n="">n</c-><c-

                      o="">*</c-><c- mi="">2</c-> <c- o="">+</c-> <c- n="">n</c->
                    <c- o="">+</c-> <c- mi="">1</c-></code> bytes instead of <code

                    class="highlight"><c- n="">n</c-><c- o="">*</c-><c- k="">sizeof</c-><c-

                      p="">(</c-><c- b="">char</c-><c- p="">)</c-> <c- o="">+</c->
                    <c- n="">n</c-> <c- o="">+</c-> <c- mi="">1</c-></code>
                  bytes.<br>
                  <br>
                </del></p>
					 <p style="color: red"><strong>Matt: Arthur has been informed both on the
                  reflector and the reference implementation's github that this situation is only
                  for types with sizes equal to uint_8, and that this limitation could be worked around
                  if it were important to an implementation. It has no relevance to the issue and as such comes across as creating FUD.<br>
                  <a href="https://github.com/mattreecebentley/plf_hive/issues/19">https://github.com/mattreecebentley/plf_hive/issues/19</a><br>
                  Lewg reflector, 4/05/2022, 1:42 pm, My reply Re:
                  [isocpp-lib-ext] Notes on P0447R20, was Re: Info+paper for
                  hive discussion Tuesday 5th 11am pacific time (<a href="https://lists.isocpp.org/lib-ext/2022/05/23129.php">https://lists.isocpp.org/lib-ext/2022/05/23129.php</a>)<br>
                  <br>
</strong></p>
            </li>
          </ul>
        </li>
      </ul>
      <p>It’s kind of fun that you’re allowed to set a very small maximum block
        size, and thus a hive can be used to simulate a traditional "rope" of
        fixed-capacity blocks:</p>
      <pre class="highlight"><c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c- n="">h</c-><c- p="">(</c-><c-

n="">std</c-><c- o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">3</c-><c-

p="">,</c-> <c- mi="">3</c-><c- p="">));</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">,</c-><c- mi="">7</c-><c-

p="">,</c-><c- mi="">8</c-><c- p="">});</c->  <c- c1="">// [1 2 3] [4 5 6] [7 8 _]</c->
</pre>
      <p>It’s kind of fun; but I claim that it is not <em>useful enough</em> to
        justify its cost, in brain cells nor in CPU time.</p>
      <p>Imagine if <code class="highlight"><c- n="">std</c-><c- o="">::</c-><c-

            n="">vector</c-></code> provided this max-block-capacity API!</p>
      <pre class="highlight"><c- c1="">// If vector provided hive’s API...</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">vector</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">v</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">};</c->  <c- c1="">// [1 2]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">({</c-><c- mi="">5</c-><c-

p="">,</c-> <c- mi="">8</c-><c- p="">});</c->           <c- c1="">// [1 2 _ _ _]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">});</c->       <c- c1="">// [1 2 3 4 5]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">push_back</c-><c- p="">(</c-><c- mi="">6</c-><c-

p="">);</c->              <c- c1="">// [1 2 3 4 5 6 _ _]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">push_back</c-><c- p="">(</c-><c- mi="">7</c-><c-

p="">);</c->              <c- c1="">// [1 2 3 4 5 6 7 _]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">push_back</c-><c- p="">(</c-><c- mi="">8</c-><c-

p="">);</c->              <c- c1="">// [1 2 3 4 5 6 7 8]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">push_back</c-><c- p="">(</c-><c- mi="">9</c-><c-

p="">);</c->              <c- c1="">// throws length_error, since allocating a larger block isn’t allowed</c->
</pre>
      <p><del>No, the real-world <code

            class="highlight"><c- n="">vector</c-></code> sensibly says that it
          should just keep geometrically resizing until the underlying allocator
          conks out. </del>In my opinion, <code class="highlight"><c- n="">hive</c-></code>
        should behave the same way. Let the <em>allocator</em> decide how many
        bytes is too much to allocate at once. Don’t make it the container’s
        problem.</p>
      <p style="color: red"><strong>Matt: In the real world devs often don't use vector for this exact
          reason. Most high-performance developers, games industry included, are
          Required to keep allocation amounts in check. What Arthur is
          suggesting has no practical value.</strong></p>
      <p class="note" role="note"><span>Note:</span> Discussion in SG14
        (2022-06-08) suggested that maybe <code class="highlight"><c- n="">hive_limits</c-><c-

            p="">(</c-><c- mi="">16</c-><c- p="">,</c-> <c- mi="">16</c-><c- p="">)</c-></code>
        would be useful for SIMD processing; but that doesn’t hold up well under
        scrutiny. <del>The reference
          implementation doesn’t store <code class="highlight"><c- n="">T</c-></code>
          objects contiguously</del>. And even if <code class="highlight"><c-

            n="">hive_limits</c-><c- p="">(</c-><c- mi="">16</c-><c- p="">,</c->
          <c- mi="">16</c-><c- p="">)</c-></code> were useful (which it’s not),
        that rationale wouldn’t apply to <code class="highlight"><c- n="">hive_limits</c-><c-

            p="">(</c-><c- mi="">23</c-><c- p="">,</c-> <c- mi="">29</c-><c- p="">)</c-></code>
        and so on.</p>
      <p style="color: red"><strong>Matt: I have evaluated my position on
          SIMD usage clearly in the paper in both past and present versions. The
          reference implementation stores objects contiguously within a
          block's capacity, until an erasure or splice occurs - then, any
          elements before and after that erasure/splice are no longer guaranteed to be contiguous.
          Therefore, SIMD processing is only possible when the minimum and
          maximum block capacity limits are a multiple of the SIMD command's
          width, and either (a) no erasures have occurred, or
          (b) an equal number of erasures and insertions have occurred, or (c) a
          number of consecutive erasures equal to the SIMD width, starting at a
          SIMD width boundary, occurred.
        </strong></p>
      <h3 class="heading settled" data-level="3.2" id="motivation-bigo"><del><span

            class="secno">3.2. </span><span class="content">Max block size
            causes O(n) behavior</span></del></h3>
      <h4 class="heading settled" data-level="3.2.1" id="motivation-bigo-1"><span

          style="text-decoration: line-through;"><span class="secno">3.2.1. </span><span

            class="content">Example 1</span></span></h4>
      <p class="note" role="note"><del>Note:
          The quadratic behavior shown below was <i>previously</i> present in
          Matt Bentley’s reference implementation (as late as <a href="https://github.com/mattreecebentley/plf_hive/blob/94862621b2466735989c88dec5b7b23a6e04e757/plf_hive.h">git
            commit 9486262</a>), but was fixed in <a href="https://github.com/mattreecebentley/plf_hive/commit/7ac1f03abd9aebfae242ba7fe3c22ab1115550e9">git
            commit 7ac1f03</a> by renumbering the blocks less often.</del></p>
      <p><del>Consider this program
          parameterized on <code class="highlight"><c- n="">N</c-></code>:</del></p>
      <pre class="highlight"><del><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">(</c-><c- n="">std</c-><c- o="">::</c-><c- n="">hive_limits</c-><c-

p="">(</c-><c- mi="">3</c-><c- p="">,</c-> <c- mi="">3</c-><c- p="">));</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">(</c-><c- n="">N</c-><c-

p="">,</c-> <c- mi="">1</c-><c- p="">);</c-> <c- c1="">// [1 1 1] [1 1 1] [1 1 1] [...</c->
<c- k="">while</c-> <c- p="">(</c-><c- o="">!</c-><c- n="">h</c-><c- p="">.</c-><c-

n="">empty</c-><c- p="">())</c-> <c- p="">{</c->
    <c- n="">h</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">.</c-><c- n="">begin</c-><c- p="">());</c->
<c- p="">}</c->
</del></pre>
      <p><del>This loop takes O(<code class="highlight"><c-

              n="">N</c-></code><sup>2</sup>) time to run! The reason is that <code

            class="highlight"><c- n="">hive</c-></code>'s active blocks are
          stored in a linked list, but also <em>numbered</em> in sequential
          order starting from 1; those "serial numbers" are required by <code class="highlight"><c-

              n="">hive</c-><c- o="">::</c-><c- n="">iterator</c-></code>'s <code

            class="highlight"><c- k="">operator</c-><c- o="">&lt;</c-></code>.
          (Aside: I don’t think <code class="highlight"><c- k="">operator</c-><c-

              o="">&lt;</c-></code> should exist either, but my understanding is
          that that’s already been litigated.)</del></p>
      <p><del>Every time you <code class="highlight"><c-

              n="">erase</c-></code> the last element from a block (changing <code

            class="highlight"><c- p="">[</c-><c- n="">_</c-> <c- n="">_</c-> <c-

              mi="">1</c-><c- p="">]</c-></code> into <code class="highlight"><c-

              p="">[</c-><c- n="">_</c-> <c- n="">_</c-> <c- n="">_</c-><c- p="">]</c-></code>),
          you need to move the newly unused block from the active block list to
          the unused block list. And then you need to renumber all the
          subsequent blocks. Quoting P0447R20’s specification of <code class="highlight"><c-

              n="">erase</c-></code>:</del></p>
      <blockquote> <del><i>Complexity:</i>
          Constant if the active block within which <code class="highlight"><c-

              n="">position</c-></code> is located does not become empty as a
          result of this function call. If it does become empty, at worst linear
          in the number of subsequent blocks in the iterative sequence. </del></blockquote>
      <p><del>Since this program sets
          the max block capacity to 3, it will hit the linear-time case once for
          every three erasures. Result: quadratic running time.</del></p>
      <h4 class="heading settled" data-level="3.2.2" id="motivation-bigo-2"><span

          style="text-decoration: line-through;"><span class="secno">3.2.2. </span><span

            class="content">Example 2</span></span></h4>
      <p class="note" role="note"><del>Note:
          The quadratic behavior shown below is <i>currently</i> present in
          Matt Bentley’s reference implementation, as of <a href="https://github.com/mattreecebentley/plf_hive/blob/ef9bad9c83919c9728a7ce99b98992ce60af0438/plf_hive.h">git
            commit ef9bad9</a>.</del></p>
      <p><del>Consider this program
          parameterized on <code class="highlight"><c- n="">N</c-></code>:</del></p>
      <pre class="highlight"><del><c- n="">plf</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">({</c-><c- mi="">4</c-><c-

p="">,</c-> <c- mi="">4</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="">N</c-><c-

p="">;</c-> <c- o="">++</c-><c- n="">i</c-><c- p="">)</c-> <c- p="">{</c->
    <c- n="">h</c-><c- p="">.</c-><c- n="">insert</c-><c- p="">(</c-><c- mi="">1</c-><c-

p="">);</c->
    <c- n="">h</c-><c- p="">.</c-><c- n="">insert</c-><c- p="">(</c-><c- mi="">2</c-><c-

p="">);</c->
<c- p="">}</c->
<c- n="">erase</c-><c- p="">(</c-><c- n="">h</c-><c- p="">,</c-> <c- mi="">1</c-><c-

p="">);</c-> <c- c1="">// [_ 2 _ 2] [_ 2 _ 2] [_ 2 _ 2] [...</c->
<c- k="">while</c-> <c- p="">(</c-><c- o="">!</c-><c- n="">h</c-><c- p="">.</c-><c-

n="">empty</c-><c- p="">())</c-> <c- p="">{</c->
    <c- n="">h</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">.</c-><c- n="">begin</c-><c- p="">());</c->
<c- p="">}</c->
</del></pre>
      <p><del>The final loop takes O(<code class="highlight"><c- n="">N</c-></code><sup>2</sup>) time to run!
          The reason is that in the reference implementation, <code class="highlight"><c-

              n="">hive</c-></code>'s list of blocks-with-erasures is singly
          linked. Every time you <code class="highlight"><c- n="">erase</c-></code>
          the last element from a block (changing <code class="highlight"><c- p="">[</c-><c-

              n="">_</c-> <c- n="">_</c-> <c- n="">_</c-> <c- mi="">2</c-><c-

              p="">]</c-></code> into <code class="highlight"><c- p="">[</c-><c-

              n="">_</c-> <c- n="">_</c-> <c- n="">_</c-> <c- n="">_</c-><c-

              p="">]</c-></code>), you need to unlink the newly empty block from
          the list of blocks with erasures; and thanks to how we set up this
          snippet, the current block will always happen to be at the end of that
          list! So each <code class="highlight"><c- n="">erase</c-></code>
          takes O(<code class="highlight"><c- n="">h</c-><c- p="">.</c-><c- n="">size</c-><c-

              p="">()</c-></code>) time, and the overall program takes O(<code class="highlight"><c-

              n="">N</c-></code><sup>2</sup>) time.</del></p>

      <p><del>Such "secret quadratic
          behavior" is caused <em>primarily</em> by how <code class="highlight"><c-

              n="">hive</c-></code> permits the programmer to set a max block
          size. If we get rid of the max block size, then the implementation is
          free to allocate larger blocks, and so we’ll hit the linear-time cases
          geometrically less often — we’ll get amortized O(<code class="highlight"><c-

              n="">N</c-></code>) instead of O(<code class="highlight"><c- n="">N</c-></code><sup>2</sup>).</del></p>
      <div class="note" role="note"><del>
          Using my proposed <code class="highlight"><c- n="">hive</c-></code>,
          it will still be possible to simulate a rope of fixed-size blocks; but
          the programmer will have to go pretty far out of their way. There will
          be no footgun analogous to <code class="highlight"><c- n="">std</c-><c-

              o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

              o="">&gt;</c-><c- p="">({</c-><c- mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c-

              p="">,</c-><c- mi="">3</c-><c- p="">},</c-> <c- p="">{</c-><c- mi="">3</c-><c-

              p="">,</c-><c- mi="">3</c-><c- p="">})</c-></code>. </del>
        <pre class="highlight"><del><c-

k="">auto</c-> <c- n="">make_block</c-> <c- o="">=</c-> <c- p="">[]()</c-> <c- p="">{</c->
    <c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">;</c->
    <c- n="">h</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">3</c-><c-

p="">);</c->
    <c- k="">return</c-> <c- n="">h</c-><c- p="">;</c->
<c- p="">};</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c- n="">make_block</c-><c-

p="">());</c-> <c- c1="">// [_ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c- n="">make_block</c-><c-

p="">());</c-> <c- c1="">// [_ _ _] [_ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c- n="">make_block</c-><c-

p="">());</c-> <c- c1="">// [_ _ _] [_ _ _] [_ _ _]</c->
<c- c1="">// ...</c-></del><br>
</pre> </div>
      <p  style="color: red"><strong>Matt:
          None of the above behaviours were present in the implementation at the
          time of publication. The second behaviour had already been removed
          from beta at the time when I reviewed Arthur's draft paper, the first
          no longer existed in the official release and shouldn't have been
          mentioned above, and is FUD. As mentioned at the start of this document, neither
          formed quadratic behaviour.</strong></p>

      <h3 class="heading settled" data-level="3.3"><span class="secno">3.3. </span><span

          class="content" style="text-decoration: line-through;">Move semantics
          are arguably unintuitive</span></h3>
      <p style="color: red"><strong>Matt: The transfer of capacity limits between hive instances
          follows much the same rules as allocator transfer - which makes sense since
          the two may be related in the real world. The paper has been updated with details of this.
			 In other words, move constructors and copy constructors transfer the limits, as do swap and
          operator = &amp;&amp;, operator = &amp; doesn't, nor does splice. With
          allocators in list.splice and hive.splice, the behavior is undefined
          if get_allocator() != x.get_allocator(). With capacity_limits in
          hive.splice, the behaviour is more concrete - we throw if the source
          blocks will not fit within the destination hive's capacity_limits.<br>
        However in the default use of hive, a user will not encounter
          these behaviours, because the user does not Need to
          specify block capacity limits, unless they desire to do so - as such, knowledge of the above
          transfer information is only relevant to users specifying their own
          custom block capacity limits.<br></strong></p>
      <p>Suppose we’ve constructed a hive with min and max block capacities, and
        then we assign into it from another sequence in various ways.</p>
      <pre class="highlight"><c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c- n="">h</c-><c- p="">(</c-><c-

n="">std</c-><c- o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">3</c-><c-

p="">,</c-> <c- mi="">3</c-><c- p="">));</c->  <c- c1="">// empty</c->

<c- n="">h</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">});</c->                <c- c1="">// [1 2 3] [4 5 _]</c->
<c- n="">h</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c- p="">,</c-><c-

mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">,</c-><c-

mi="">5</c-><c- p="">};</c->                      <c- c1="">// [1 2 3] [4 5 _]</c->

<c- n="">h</c-><c- p="">.</c-><c- n="">assign_range</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- p="">{</c-><c- mi="">1</c-><c- p="">,</c-><c-

mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">,</c-><c-

mi="">5</c-><c- p="">});</c-> <c- c1="">// [1 2 3] [4 5 _]</c->

<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">d</c-> <c- o="">=</c-> <c- n="">h</c-><c- p="">;</c->                 <c-

c1="">// [1 2 3] [4 5 _]</c->

<p style="color: red; font-size: 13pt"><b>Matt: It should be noted here that the C++ resolution rules
will change the = operation on a newly-constructed type (as above) to a
copy-construction op instead, and since the copy constructor
tranfers the block limits whereas copy assignment does not, 
this is the result. This is unfortunate, but the same problem 
occurs with allocators with propogate_on_copy_assignment == false, 
in that the copy assignment and copy construction will involve 
different transfer semantics. Removing block limits does not
'fix' the resolution scenario.</b></p>


<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">d</c-> <c- o="">=</c-> <c- n="">std</c-><c- o="">::</c-><c-

n="">move</c-><c- p="">(</c-><c- n="">h</c-><c- p="">);</c->      <c- c1="">// [1 2 3] [4 5 _]</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">d</c-><c- p="">(</c-><c- n="">h</c-><c- p="">,</c-> <c-

n="">Alloc</c-><c- p="">());</c->            <c- c1="">// [1 2 3] [4 5 _]</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">d</c-><c- p="">(</c-><c- n="">std</c-><c- o="">::</c-><c-

n="">move</c-><c- p="">(</c-><c- n="">h</c-><c- p="">),</c-> <c- n="">Alloc</c-><c-

p="">());</c-> <c- c1="">// [1 2 3] [4 5 _]</c->

<c- c1="">// BUT:</c->

<c- n="">h</c-> <c- o="">=</c-> <c-

n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">};</c-> <c- c1="">// [1 2 3 4 5]<br><br><strong></strong></c-><c-

c1=""><p style="color: red; font-size: 13pt"><b>Matt: In this case the compiler is selecting a move operation instead of a
copy operation because that's what the C++ standard's overload resolution rules
say it should do with a prvalue (see notes here:
https://en.cppreference.com/w/cpp/language/move_assignment).
In which case it copies across the block limits along with the blocks, 
which in the above case are the default block limits.
The behaviour is correct and well-defined, non-problematic. While the
result might not be what the user expected, ultimately the above is bad
programming, as it involves needless construction of a temporary hive
and I would be surprised/disturbed to see this in production code.
I would expect a reasonable programmer to use an initializer_list or similar.
Removing min/max block capacity limits does not 'fix' this situation
since allocators have the same issue - their trasnfer/non-transfer behaviour
is necessarily different when copying instead of moving.</b></p><br>&nbsp;<c-

c1="">// OR</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h2</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">};</c->
<del><c- n="">h</c-> <c- o="">=</c-> <c-

n="">h2</c-><c- p="">;</c->                   </del><c- c1=""><del>// [1 2 3 4 5]</del><br><br></c->
<p style="color: red; font-size: 12pt"><strong>Matt: Incorrect. The above is an assignment of a named lvalue, and C++ resolution
rules mean it should be copied, not moved.
This is confirmed under GCC, in both debug and -O2. [1 2 3] [4 5 _].
If a compiler is doing otherwise, the compiler is operating outside
of the C++ resolution rules IMHO.
</strong></p>&nbsp;<c-

c1="">// OR</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h2</c-> <c- o="">=</c-> <c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">};</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">swap</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">,</c-> <c- n="">h2</c-><c- p="">);</c->         <c- c1="">// [1 2 3 4 5]</c->

<c- c1="">// BUT AGAIN:</c->

<c- n="">h</c-> <c- o="">=</c-> <c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c-

o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">3</c-><c- p="">,</c-> <c-

mi="">3</c-><c- p="">));</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">});</c->  <c- c1="">// throws length_error<br><br><br></c-><strong></strong></pre>
      <p>The <i><code class="highlight"><c-

                n="">current</c-><c- o="">-</c-><c- n="">limits</c-></code></i>
          of a hive are not part of its "value," yet they still affect its
          behavior in critical ways. Worse, the capacity limits are "sticky" in
          a way that reminds me of <code class="highlight"><c- n="">std</c-><c-

              o="">::</c-><c- n="">pmr</c-></code> allocators: <em>most</em>
          modifying operations don’t affect a hive’s limits (resp. a <code class="highlight"><c-

              n="">pmr</c-></code> container’s allocator), but <em>some</em>
          operations do.</del></p>
      <p>The distinction between these two overloads of <code class="highlight"><c-

            k="">operator</c-><c- o="">=</c-></code> is particularly awkward:</p>
      <pre class="highlight"><c- n="">h</c-> <c- o="">=</c-> <c- p="">{</c-><c-

mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c-

mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">};</c->           <c- c1="">// does NOT affect h’s limits</c->
<del><c- n="">h</c-> <c- o="">=</c-> <c-

n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- p="">{</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">};</c->  <c- c1="">// DOES affect h’s limits</c-></del></p>
<p style="color: red; font-size: 12pt"><strong>Matt: Again, this is the compiler correctly resolving to a move operation on the prvalue.</strong></p></pre>
      <p style="color: red"><strong>
      Matt:
		I initially thought that this was the one portion of the document where Arthur had a point - unfortunately the point didn't only relate to the user's ability to specify a minimum/maximum block capacity specifically, but also whether the user has specified a different allocator instance in the source hive, or any other container doing the same thing. But on closer inspection it's just the compiler correctly resolving to a move operation, with the correct semantics for that move operation. Whether the user should be writing code this bad is another story - if you want to assign 1, 2, 3, 4, 5, 6 to a pre-existing hive&lt;int&gt;, you either write an insert command, use assign or operator = (initializer_list). Only a bad coder writes temporary hives to use with operator =, as (a) it looks confusing and (b) it wastes performance by needlessly constructing a temporary hive - if the compiler doesn't somehow manage to optimize the temporary out at -O2 (this won't happen at -O0). A non-temporary hive which is used elsewhere in code won't of course trigger the overload resolution to move.<br>
      <br>

		hive limits do not (and should not) have an equivalent to <code>propagate_on_container_copy_assignment</code>, as we wish to allow for elements to be copied between hives of dissimilar limits without changing those limits, so these will never be copied on operator = (hive &amp;) usage. I did query others regarding whether it would be worth copying hive limits on copy assignment, the status quo was the preferred solution.<br>
		  Copy &amp; move constructors for containers typically allow the user to specify a non-source allocator, however this has been considered overkill for hive limits. Status quo is that if the user wants to specify new hive limits when copy constructing, they can:<br>
<code>hive&lt;int&gt; h(hive_limits(10,50)); h = other_hive;</code><br>
And if they want to specify new capacity limits when moving another hive, they can:<br>
<code>hive&lt;int&gt; h(std::move(other_hive)); r.reshape(10, 50);</code>
This avoids needless additional overloads for the copy and move constructor.</strong></p>
      <h3 class="heading settled" data-level="3.4"><span class="secno">3.4. </span><span

          class="content"><code class="highlight"><strike><c- n="">splice</c-></code> is
          O(n), and can throw</strike>
        </span></h3>
          <p style="color: red"><strong>Matt: As is stated in the current paper, and was stated in the draft
          papers for D0447R20 which were publicly available, and as is obvious
          from the implementation, it is at-worst O(n) in the number of memory
          blocks and at best O(1). In the reference implementation it will only be O(n) if the user is using user-defined block capacity limits, and if these limits differ significantly in the source.<br>
		  However in the event that a hive is
          implemented as a vector of pointers to element blocks +
          metadata, splice would always be O(n) in the number of memory blocks
          due to the need to copy pointers and remove said pointers from the
          source hive. So time complexity of splice is not improved by removing the
          hive limit functionality.<br>
          Also as explained in above sections, splice behaviour for hive limits is largely analogous to splice behaviour for allocators. In the case of allocators, UB is caused if the allocators do not match. In the case of hive limits, throw is called but only if blocks from source do not fit within the hive_limits of destination.           <a href="https://isocpp.org/files/papers/P0447R20.html#design">https://isocpp.org/files/papers/P0447R20.html#design</a> under Additional
          notes on Specific functions, Splice<br>
          <br>
</strong></p>
      <p><del>In P0447R20, <code class="highlight"><c-

              n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c- n="">h2</c-><c-

              p="">)</c-></code> is a "sticky" operation: it does not change <code

            class="highlight"><c- n="">h</c-></code>'s limits. This means that
          if <code class="highlight"><c- n="">h2</c-></code> contains any
          active blocks larger than <code class="highlight"><c- n="">h</c-><c-

              p="">.</c-><c- n="">block_capacity_limits</c-><c- p="">().</c-><c-

              n="">max</c-></code>, then <code class="highlight"><c- n="">h</c-><c-

              p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c- n="">h2</c-><c-

              p="">)</c-></code> will fail and throw <code class="highlight"><c-

              n="">length_error</c-></code>! This is a problem on three levels:</del></p>
      <ul>
        <li data-md="">
          <p><del>Specification
              speedbump: Should we say something about the state of <code class="highlight"><c-

                  n="">h2</c-></code> after the throw? for example, should we
              guarantee that any too-large blocks not transferred out of <code

                class="highlight"><c- n="">h2</c-></code> will remain in <code

                class="highlight"><c- n="">h2</c-></code>, kind of like what
              happens in <code class="highlight"><c- n="">std</c-><c- o="">::</c-><c-

                  n="">set</c-><c- o="">::</c-><c- n="">merge</c-></code>? Or
              should we leave it unspecified?</del></p>
        </li>
        <li data-md="">
          <p><del>Correctness pitfall: <code

                class="highlight"><c- n="">splice</c-></code> "should" just
              twiddle a few pointers. The idea that it might actually <em>fail</em>
              is not likely to occur to the working programmer.</del></p>
        </li>
        <li data-md="">
          <p><del>Performance
              pessimization: Again, <code class="highlight"><c- n="">splice</c-></code>
              "should" just twiddle a few pointers. But P0447R20’s specification
              requires us to traverse <code class="highlight"><c- n="">h2</c-></code>
              looking for too-large active blocks. This adds an O(n) step that
              doesn’t "need" to be there.</del></p>
        </li>
      </ul>
      <p><del>If my proposal is adopted,
          <code class="highlight"><c- n="">hive</c-><c- o="">::</c-><c- n="">splice</c-></code>
          will be "Throws: Nothing," just like <code class="highlight"><c- n="">list</c-><c-

              o="">::</c-><c- n="">splice</c-></code>.</del></p>
      <p class="note" role="note"><del>Note:
          I would expect that both <code class="highlight"><c- n="">hive</c-><c-

              o="">::</c-><c- n="">splice</c-></code> and <code class="highlight"><c-

              n="">list</c-><c- o="">::</c-><c- n="">splice</c-></code> <em>ought</em>
          to throw <code class="highlight"><c- n="">length_error</c-></code> if
          the resulting container would exceed <code class="highlight"><c- n="">max_size</c-><c-

              p="">()</c-></code> in size; but I guess that’s intended to be
          impossible in practice.</del></p>
      <h3 class="heading settled" data-level="3.5" id="motivation-bloat"><del><span

            class="secno">3.5. </span><span class="content"><code class="highlight"><c-

                n="">hive_limits</c-></code> causes constructor overload set
            bloat</span></del></h3>
      <p><del>Every STL container’s
          constructor overload set is "twice as big as necessary" because of the
          duplication between <code class="highlight"><c- n="">container</c-><c-

              p="">(</c-><c- n="">Args</c-><c- p="">...)</c-></code> and <code

            class="highlight"><c- n="">container</c-><c- p="">(</c-><c- n="">Args</c-><c-

              p="">...,</c-> <c- n="">Alloc</c-><c- p="">)</c-></code>. <code

            class="highlight"><c- n="">hive</c-></code>'s constructor overload
          set is "four times as big as necessary" because of the duplication
          between <code class="highlight"><c- n="">container</c-><c- p="">(</c-><c-

              n="">Args</c-><c- p="">...)</c-></code> and <code class="highlight"><c-

              n="">container</c-><c- p="">(</c-><c- n="">Args</c-><c- p="">...,</c->
            <c- n="">hive_limits</c-><c- p="">)</c-></code>.<br>
        </del></p>
        <p style="color: red"><strong>Matt: All additional overloads required by hive_limits are
          implemented by way of constructor delegation, meaning there is no code
          bloat. This is not only specified in the implementation, but in the
          Technical Specification of Hive itself.<br>
          <br>
</strong></p>
      <p><del>P0447R20 <code class="highlight"><c-

              n="">hive</c-></code> has 18 constructor overloads. My proposal
          removes 7 of them. (Of course, we could always eliminate these same 7
          constructor overloads without doing anything else to P0447R20. If this
          were the <em>only</em> complaint, my proposal would be
          undermotivated.)</del></p>
      <p><del>Analogously: Today there
          is no constructor overload for <code class="highlight"><c- n="">vector</c-></code>
          that sets the capacity in one step; it’s a multi-step process. Even
          for P0447R20 <code class="highlight"><c- n="">hive</c-></code>,
          there’s no constructor overload that sets the overall capacity in one
          step — even though overall capacity is more important to the average
          programmer than min and max block capacities!</del></p>
      <pre class="highlight"><del><c- c1="">// Today’s multi-step process for vector</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">vector</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">v</c-><c- p="">;</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">12</c-><c-

p="">);</c->            <c- c1="">// [_ _ _ _ _ _ _ _ _ _ _ _]</c->
<c- n="">v</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">});</c->  <c-

c1="">// [1 2 3 4 5 6 _ _ _ _ _ _]</c->

<c- c1="">// Today’s multi-step process for hive</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">(</c-><c- n="">std</c-><c-

o="">::</c-><c- n="">hive_limits</c-><c- p="">(</c-><c- mi="">12</c-><c- p="">,</c-> <c-

n="">h</c-><c- p="">.</c-><c- n="">block_capacity_hard_limits</c-><c- p="">().</c-><c-

n="">max</c-><c- p="">));</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c- mi="">12</c-><c-

p="">);</c->            <c- c1="">// [_ _ _ _ _ _ _ _ _ _ _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">.</c-><c- n="">block_capacity_hard_limits</c-><c- p="">());</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">});</c->  <c-

c1="">// [1 2 3 4 5 6 _ _ _ _ _ _ _]</c->

<c- c1="">// Today’s (insufficient) single-step process for hive</c->
<c- c1="">// fails to provide a setting for overall capacity</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">({</c-><c- mi="">1</c-><c- p="">,</c-><c-

mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">,</c-><c-

mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">},</c-> <c- p="">{</c-><c- mi="">3</c-><c-

p="">,</c-> <c- mi="">5</c-><c- p="">});</c->
                          <c- c1="">// [1 2 3 4 5] [6 _ _]</c->
</del></pre>
      <p><del>If my proposal is adopted,
          the analogous multi-step process will be:</span></p>
      <pre class="highlight"><del><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">(</c-><c- mi="">12</c-><c-

p="">,</c-> <c- mi="">12</c-><c- p="">);</c->      <c- c1="">// [_ _ _ _ _ _ _ _ _ _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">assign</c-><c- p="">({</c-><c- mi="">1</c-><c-

p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c- mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">,</c-><c- mi="">6</c-><c- p="">};</c-> <c- c1="">// [1 2 3 4 5 6 _ _ _ _ _ _]</c->
</del></pre>
      <h3 class="heading settled" data-level="3.6"><del><span

            class="secno">3.6. </span><span class="content"><code class="highlight"><c-

                n="">hive_limits</c-></code> introduces unnecessary UB<br>
            <br>
          </span></del></h3>
			 <p style="color: red"><strong>Matt: The issues Arthur has raised
          here were previously discussed in a LEWG meeting and resolved via the
        block_capacity_hard_limits()
          static member function, which is detailed in the paper and was in the
          publicly available draft version
          of that paper for a long time.<br>
          <a href="https://isocpp.org/files/papers/P0447R20.html#design">https://isocpp.org/files/papers/P0447R20.html#design</a> under Additional
          notes on Specific functions, block_capacity_hard_limits()</strong></p><span

          style="text-decoration: line-through;"><span class="content"><br>
          </span></span>
      <p><del><a data-link-type="biblio"

href="#biblio-d0447r20">[D0447R20]</a> currently says ([hive.overview]/5):</del></p>
      <blockquote><del> If
          user-specified limits are supplied to a function which are not within
          an implementation’s <i>hard limits</i>, or if the user-specified
          minimum is larger than the user-specified maximum capacity, the
          behaviour is undefined. </del></blockquote>
      <p><del>In Matt Bentley’s
          reference implementation, this program will manifest its UB by
          throwing <code class="highlight"><c- n="">std</c-><c- o="">::</c-><c-

              n="">length_error</c-></code>.</del></p>
      <p><del>The following program’s
          behavior is always undefined:</del></p>
      <pre class="highlight"><del><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">({</c-><c- mi="">0</c-><c-

p="">,</c-> <c- n="">SIZE_MAX</c-><c- p="">});</c-> <c- c1="">// UB! Throws.</c->
</del></pre>
      <p><del>Worse, the following
          program’s definedness hinges on whether the user-provided max <code class="highlight"><c-

              mi="">1000</c-></code> is greater than the implementation-defined
          <code class="highlight"><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">char</c-><c-

              o="">&gt;::</c-><c- n="">block_capacity_hard_limits</c-><c- p="">().</c-><c-

              n="">max</c-></code>. The reference implementation’s <code class="highlight"><c-

              n="">hive</c-><c- o="">&lt;</c-><c- b="">char</c-><c- o="">&gt;::</c-><c-

              n="">block_capacity_hard_limits</c-><c- p="">().</c-><c- n="">max</c-></code>
          is <code class="highlight"><c- mi="">255</c-></code>, so this program
          has undefined behavior (<a href="https://godbolt.org/z/naT7GqEMo">Godbolt</a>):</del></p>
      <pre class="highlight"><del><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">char</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">({</c-><c- mi="">10</c-><c-

p="">,</c-> <c- mi="">1000</c-><c- p="">});</c-> <c- c1="">// UB! Throws.</c->
</del></pre>
      <p><del>There are two problems
          here. The first is trivial to solve: P0447R20 adds to the set of
          unnecessary library UB. We could fix that by simply saying that the
          implementation must <em>clamp the provided limits</em> to the hard
          limits; this will make <code class="highlight"><c- n="">h</c-><c- p="">.</c-><c-

              n="">reshape</c-><c- p="">({</c-><c- mi="">0</c-><c- p="">,</c-> <c-

              n="">SIZE_MAX</c-><c- p="">})</c-></code> well-defined, and make <code

            class="highlight"><c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c-

              p="">({</c-><c- mi="">10</c-><c- p="">,</c-> <c- mi="">1000</c-><c-

              p="">})</c-></code> UB only in the unlikely case that the
          implementation doesn’t support <em>any</em> block sizes in the range
          [10, 1000]. We could even mandate that the implementation <em>must</em>
          throw <code class="highlight"><c- n="">length_error</c-></code>,
          instead of having UB.</del></p>
      <p><del>The second problem is
          bigger: <code class="highlight"><c- n="">hive_limits</c-></code>
          vastly increases the "specification surface area" of <code class="highlight"><c-

              n="">hive</c-></code>'s API.</del></p>
      <ul>
        <li data-md="">
          <p><del>Every constructor
              needs to specify (or UB) what happens when the supplied <code class="highlight"><c-

                  n="">hive_limits</c-></code> are invalid.</del></p>
        </li>
        <li data-md="">
          <p><del><code class="highlight"><c-

                  n="">reshape</c-></code> needs to specify (or UB) what happens
              when the supplied <code class="highlight"><c- n="">hive_limits</c-></code>
              are invalid.</del></p>
        </li>
        <li data-md="">
          <p><del><code class="highlight"><c-

                  n="">splice</c-></code> needs to specify what happens when the
              two hives' <i><code class="highlight"><c- n="">current</c-><c- o="">-</c-><c-

                    n="">limits</c-></code></i> are incompatible.</del></p>
        </li>
        <li data-md="">
          <p><del>The special members —
              <code class="highlight"><c- n="">hive</c-><c- p="">(</c-><c- k="">const</c->
                <c- n="">hive</c-><c- o="">&amp;</c-><c- p="">)</c-></code>, <code

                class="highlight"><c- n="">hive</c-><c- p="">(</c-><c- n="">hive</c-><c-

                  o="">&amp;&amp;</c-><c- p="">)</c-></code>, <code class="highlight"><c-

                  k="">operator</c-><c- o="">=</c-><c- p="">(</c-><c- k="">const</c->
                <c- n="">hive</c-><c- o="">&amp;</c-><c- p="">)</c-></code>, <code

                class="highlight"><c- k="">operator</c-><c- o="">=</c-><c- p="">(</c-><c-

                  n="">hive</c-><c- o="">&amp;&amp;</c-><c- p="">)</c-></code>,
              <code class="highlight"><c- n="">swap</c-></code> — need to
              specify their effect on each operand’s <i><code class="highlight"><c-

                    n="">current</c-><c- o="">-</c-><c- n="">limits</c-></code></i>.
              For example, is <code class="highlight"><c- k="">operator</c-><c-

                  o="">=</c-><c- p="">(</c-><c- k="">const</c-> <c- n="">hive</c-><c-

                  o="">&amp;</c-><c- p="">)</c-></code> permitted to preserve
              its left-hand side’s <i><code class="highlight"><c- n="">current</c-><c-

                    o="">-</c-><c- n="">limits</c-></code></i>, in the same way
              that <code class="highlight"><c- n="">vector</c-><c- o="">::</c-><c-

                  k="">operator</c-><c- o="">=</c-><c- p="">(</c-><c- k="">const</c->
                <c- n="">vector</c-><c- o="">&amp;</c-><c- p="">)</c-></code> is
              permitted to preserve the left-hand side’s capacity? The Standard
              needs to specify this.</del></p>
        </li>
        <li data-md="">
          <p><del><code class="highlight"><c-

                  n="">reshape</c-></code> needs to think about how to restore
              the hive’s invariants if an exception is thrown. (See below.)</del></p>
        </li>
      </ul>
      <p><del>All this extra
          specification effort is costly, for LWG and for vendors. My "Proposed
          Wording" is mostly deletions.<br>
          <br>
        </del>
		  </p>
		  <p style="color: red"><strong>MATT: If you look at the code - which Arthur has in
          detail, since he has submitted dozens of Issues on the hive github
          page - the additional implementation effort is minimal, at best. Additional constructors via delegation, the 2 single-line functions for obtaining hive limits, the reshape function. And since most major vendors have suggested that they will either use the
          existing hive codebase, or use it as a reference or starting point,
          there is no real additional cost to them. The work is done. This latter info was
          publicly available on the LEWG reflector.<br>
          See: Re: [isocpp-lib-ext] Is hive priority worth the cost? (Matt
          Bentley, Mon, 11 Apr 2022 12:51) (<a href="https://lists.isocpp.org/lib-ext/2022/04/22987.php">https://lists.isocpp.org/lib-ext/2022/04/22987.php</a>)<br>
        </strong></p>
      <p><strong><br>
        </strong></p>
      <strong> </strong>
      <p><del>When I say "<code class="highlight"><c-

              n="">reshape</c-></code> needs to think about how to restore the
          hive’s invariants," I’m talking about this example:</del></p>
      <pre class="highlight"><del><c- n="">std</c-><c-

o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- n="">W</c-><c- o="">&gt;</c-> <c-

n="">h</c-><c- p="">({</c-><c- mi="">1</c-><c- p="">,</c-><c- mi="">2</c-><c- p="">,</c-><c-

mi="">3</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">},</c-> <c-

p="">{</c-><c- mi="">4</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">});</c-> <c-

c1="">// [1 2 3 4] [5 _ _ _]</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">({</c-><c- mi="">5</c-><c-

p="">,</c-><c- mi="">5</c-><c- p="">});</c->  <c- c1="">// suppose W(W&amp;&amp;) can throw</c->
</del></pre>
      <p><del>Suppose <code class="highlight"><c-

              n="">W</c-></code>'s move constructor is throwing (and for the
          sake of simplicity, assume <code class="highlight"><c- n="">W</c-></code>
          is move-only, although the same problem exists for copyable types
          too). The hive needs to get from <code class="highlight"><c- p="">[</c-><c-

              mi="">1</c-> <c- mi="">2</c-> <c- mi="">3</c-> <c- mi="">4</c-><c-

              p="">]</c-> <c- p="">[</c-><c- mi="">5</c-> <c- n="">_</c-> <c-

              n="">_</c-> <c- n="">_</c-><c- p="">]</c-></code> to <code class="highlight"><c-

              p="">[</c-><c- mi="">1</c-> <c- mi="">2</c-> <c- mi="">3</c-> <c-

              mi="">4</c-> <c- mi="">5</c-><c- p="">]</c-></code>. We can start
          by allocating a block <code class="highlight"><c- p="">[</c-><c- n="">_</c->
            <c- n="">_</c-> <c- n="">_</c-> <c- n="">_</c-> <c- n="">_</c-><c-

              p="">]</c-></code> and then moving the first element over: <code

            class="highlight"><c- p="">[</c-><c- mi="">1</c-> <c- mi="">2</c->
            <c- mi="">3</c-> <c- mi="">4</c-><c- p="">]</c-> <c- p="">[</c-><c-

              mi="">5</c-> <c- n="">_</c-> <c- n="">_</c-> <c- n="">_</c-> <c-

              n="">_</c-><c- p="">]</c-></code>. Then we move over the next
          element, intending to get to <code class="highlight"><c- p="">[</c-><c-

              mi="">1</c-> <c- mi="">2</c-> <c- mi="">3</c-> <c- n="">_</c-><c-

              p="">]</c-> <c- p="">[</c-><c- mi="">5</c-> <c- mi="">4</c-> <c-

              n="">_</c-> <c- n="">_</c-> <c- n="">_</c-><c- p="">]</c-></code>;
          but that move construction might throw. If it does, then we have no
          good options. If we do as <code class="highlight"><c- n="">vector</c-></code>
          does, and simply deallocate the new buffer, then we’ll lose data
          (namely element <code class="highlight"><c- mi="">5</c-></code>). If
          we keep the new buffer, then we must update the hive’s <i><code class="highlight"><c-

                n="">current</c-><c- o="">-</c-><c- n="">limits</c-></code></i>
          because a hive with limits <code class="highlight"><c- p="">{</c-><c-

              mi="">4</c-><c- p="">,</c-><c- mi="">4</c-><c- p="">}</c-></code>
          cannot hold a block of capacity 5. But a hive with the new
          user-provided limits <code class="highlight"><c- p="">{</c-><c- mi="">5</c-><c-

              p="">,</c-><c- mi="">5</c-><c- p="">}</c-></code> cannot hold a
          block of capacity 4! So we must either lose data, or replace <code class="highlight"><c-

              n="">h</c-></code>'s <i><code class="highlight"><c- n="">current</c-><c-

                o="">-</c-><c- n="">limits</c-></code></i> with something
          "consistent but novel" such as <code class="highlight"><c- p="">{</c-><c-

              mi="">4</c-><c- p="">,</c-><c- mi="">5</c-><c- p="">}</c-></code>
          or <code class="highlight"><c- n="">h</c-><c- p="">.</c-><c- n="">block_capacity_hard_limits</c-><c-

              p="">()</c-></code>. In short: May a failed operation leave the
          hive with an "out-of-thin-air" <i><code class="highlight"><c- n="">current</c-><c-

                o="">-</c-><c- n="">limits</c-></code></i>? Implementors must
          grapple with this kind of question in many places.</del></p>
      <h3 class="heading settled" data-level="3.7" id="motivation-batches"><span

          class="secno">3.7. </span><span class="content">Un-criticism: Batches
          of input/output</span><a class="self-link" href="#motivation-batches"></a></h3>
      <p>The <code class="highlight"><c- n="">reshape</c-></code> and <code class="highlight"><c-

            n="">hive_limits</c-></code> features are not mentioned in any
        user-submitted issues on <a data-link-type="biblio" href="#biblio-plfcolony">[PlfColony]</a>,
        but there is one relevant user-submitted issue on <a data-link-type="biblio"

href="#biblio-plfstack">[PlfStack]</a>:</p>
      <blockquote>
        <p>If you know that your data is coming in groups of let’s say 100, and
          then another 100, and then 100 again etc but you don’t know when it is
          gonna stop. Having the size of the group set at 100 would allow to
          allocate the right amount of memory each time.</p>
      </blockquote>
      <p>In other words, this programmer wants to do something like this:</p>
      <pre class="highlight"><c- c1="">// OldSmart</c->
<c- b="">int</c-> <c- n="">fake_input</c-><c- p="">[</c-><c- mi="">100</c-><c- p="">]</c-> <c-

o="">=</c-> <c- p="">{};</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">;</c->
<c- n="">h</c-><c- p="">.</c-><c- n="">reshape</c-><c- p="">(</c-><c- mi="">100</c-><c-

p="">,</c-> <c- mi="">100</c-><c- p="">);</c->  <c- c1="">// blocks of size exactly 100</c->
<c- k="">while</c-> <c- p="">(</c->true<c- p="">)</c-> <c- p="">{</c->
    <c- k="">if</c-> <c- p="">(</c-><c- n="">rand</c-><c- p="">()</c-> <c- o="">%</c-> <c-

mi="">2</c-><c- p="">)</c-> <c- p="">{</c->
        <c- n="">h</c-><c- p="">.</c-><c- n="">insert</c-><c- p="">(</c-><c- n="">fake_input</c-><c-

p="">,</c-> <c- n="">fake_input</c-><c- o="">+</c-><c- mi="">100</c-><c- p="">);</c->  <c-

c1="">// read a whole block</c->
    <c- p="">}</c-> <c- k="">else</c-> <c- p="">{</c->
        <c- n="">h</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">.</c-><c- n="">begin</c-><c- p="">(),</c-> <c- n="">std</c-><c- o="">::</c-><c-

n="">next</c-><c- p="">(</c-><c- n="">h</c-><c- p="">.</c-><c- n="">begin</c-><c-

p="">(),</c-> <c- mi="">100</c-><c- p="">));</c->  <c- c1="">// erase and "unuse" a whole block</c->
    <c- p="">}</c->
<c- p="">}</c->
</pre>
      <p>If the programmer doesn’t call <code class="highlight"><c- n="">reshape</c-></code>,
        we’ll end up with <code class="highlight"><c- n="">h</c-><c- p="">.</c-><c-

            n="">capacity</c-><c- p="">()</c-> <c- o="">==</c-> <c- mi="">2</c-><c-

            o="">*</c-><c- n="">h</c-><c- p="">.</c-><c- n="">size</c-><c- p="">()</c-></code>
        in the worst case, and a single big block being used roughly like a
        circular buffer. This is actually not bad.</p>
      <p>A programmer who desperately wants the exactly-100 behavior can still
        get it, after this patch, by working only a tiny bit harder:</p>
      <pre class="highlight"><c- c1="">// NewSmart</c->
<c- b="">int</c-> <c- n="">fake_input</c-><c- p="">[</c-><c- mi="">100</c-><c- p="">]</c-> <c-

o="">=</c-> <c- p="">{};</c->
<c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c- b="">int</c-><c-

o="">&gt;</c-> <c- n="">h</c-><c- p="">;</c->
<c- k="">while</c-> <c- p="">(</c->true<c- p="">)</c-> <c- p="">{</c->
    <c- k="">if</c-> <c- p="">(</c-><c- n="">rand</c-><c- p="">()</c-> <c- o="">%</c-> <c-

mi="">2</c-><c- p="">)</c-> <c- p="">{</c->
        <c- k="">if</c-> <c- p="">(</c-><c- n="">h</c-><c- p="">.</c-><c- n="">capacity</c-><c-

p="">()</c-> <c- o="">==</c-> <c- n="">h</c-><c- p="">.</c-><c- n="">size</c-><c-

p="">())</c-> <c- p="">{</c->
            <c- n="">std</c-><c- o="">::</c-><c- n="">hive</c-><c- o="">&lt;</c-><c-

b="">int</c-><c- o="">&gt;</c-> <c- n="">temp</c-><c- p="">;</c->
            <c- n="">temp</c-><c- p="">.</c-><c- n="">reserve</c-><c- p="">(</c-><c-

mi="">100</c-><c- p="">);</c->
            <c- n="">h</c-><c- p="">.</c-><c- n="">splice</c-><c- p="">(</c-><c-

n="">temp</c-><c- p="">);</c->
        <c- p="">}</c->
        <c- n="">h</c-><c- p="">.</c-><c- n="">insert</c-><c- p="">(</c-><c- n="">fake_input</c-><c-

p="">,</c-> <c- n="">fake_input</c-><c- o="">+</c-><c- mi="">100</c-><c- p="">);</c->  <c-

c1="">// read a whole block</c->
    <c- p="">}</c-> <c- k="">else</c-> <c- p="">{</c->
        <c- n="">h</c-><c- p="">.</c-><c- n="">erase</c-><c- p="">(</c-><c- n="">h</c-><c-

p="">.</c-><c- n="">begin</c-><c- p="">(),</c-> <c- n="">std</c-><c- o="">::</c-><c-

n="">next</c-><c- p="">(</c-><c- n="">h</c-><c- p="">.</c-><c- n="">begin</c-><c-

p="">(),</c-> <c- mi="">100</c-><c- p="">));</c->  <c- c1="">// erase and "unuse" a whole block</c->
    <c- p="">}</c->
<c- p="">}</c->
</pre>
      <p style="color: red"><strong>Matt: That is... not the least bit tiny. That's the sort of code I would expect to have to make for something which is an edge-case functionality in a std::library container, not common usage stuff. The amount of code necessary to support max block capacity limits is not that much larger either.<br>
        </strong></p>
      <p>I have benchmarked these options (<a data-link-type="biblio" href="#biblio-bench">[Bench]</a>)
        and see the following results. (<code class="highlight"><c- n="">Matt</c-></code>
        is Matthew Bentley’s original <code class="highlight"><c- n="">plf</c-><c-

            o="">::</c-><c- n="">hive</c-></code>, <code class="highlight"><c-

            n="">Old</c-></code> is my implementation of P0447, <code class="highlight"><c-

            n="">New</c-></code> is my implementation of P2596; <code class="highlight"><c-

            n="">Naive</c-></code> simply omits the call to <code class="highlight"><c-

            n="">reshape</c-></code>, <code class="highlight"><c- n="">Smart</c-></code>
        ensures all blocks are size-<code class="highlight"><c- n="">N</c-></code>
        using the corresponding approach above.) With N=100, no significant
        difference between the <code class="highlight"><c- n="">Smart</c-></code>
        and <code class="highlight"><c- n="">Naive</c-></code> versions:</p>
      <pre class="highlight"><c- n="">$</c-> <c- n="">bin</c-><c- o="">/</c-><c-

n="">ubench</c-> <c- o="">--</c-><c- n="">benchmark_display_aggregates_only</c-><c-

o="">=</c->true <c- o="">--</c-><c- n="">benchmark_repetitions</c-><c- o="">=</c-><c-

mi="">5</c-> <c- o="">|</c-> <c- n="">grep</c-> <c- n="">mean</c->
<c- mi="">2022</c-><c- mo="">-06</c-><c- mi="">-10</c-><c- n="">T00</c-><c- o="">:</c-><c-

mi="">32</c-><c- o="">:</c-><c- mi="">11</c-><c- mo="">-04</c-><c- o="">:</c-><c-

mo="">00</c->
<c- n="">Running</c-> <c- n="">bin</c-><c- o="">/</c-><c- n="">ubench</c->
<c- n="">Run</c-> <c- n="">on</c-> <c- p="">(</c-><c- mi="">8</c-> <c- n="">X</c-> <c-

mi="">2200</c-> <c- n="">MHz</c-> <c- n="">CPU</c-> <c- n="">s</c-><c- p="">)</c->
<c- n="">CPU</c-> <c- n="">Caches</c-><c- o="">:</c->
  <c- n="">L1</c-> <c- n="">Data</c-> <c- mi="">32</c-> <c- n="">KiB</c-> <c- p="">(</c-><c-

n="">x4</c-><c- p="">)</c->
  <c- n="">L1</c-> <c- n="">Instruction</c-> <c- mi="">32</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x4</c-><c- p="">)</c->
  <c- n="">L2</c-> <c- n="">Unified</c-> <c- mi="">256</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x4</c-><c- p="">)</c->
  <c- n="">L3</c-> <c- n="">Unified</c-> <c- mi="">6144</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x1</c-><c- p="">)</c->
<c- n="">Load</c-> <c- n="">Average</c-><c- o="">:</c-> <c- mf="">2.28</c-><c- p="">,</c-> <c-

mf="">2.14</c-><c- p="">,</c-> <c- mf="">2.06</c->
<c- n="">BM_PlfStackIssue1_MattSmart_mean</c->        <c- mi="">93298</c-> <c- n="">ns</c->        <c-

mi="">93173</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_MattNaive_mean</c->        <c- mi="">93623</c-> <c- n="">ns</c->        <c-

mi="">93511</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_OldSmart_mean</c->        <c- mi="">114478</c-> <c- n="">ns</c->       <c-

mi="">114282</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_OldNaive_mean</c->        <c- mi="">113285</c-> <c- n="">ns</c->       <c-

mi="">113124</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_NewSmart_mean</c->        <c- mi="">128535</c-> <c- n="">ns</c->       <c-

mi="">128330</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_NewNaive_mean</c->        <c- mi="">116530</c-> <c- n="">ns</c->       <c-

mi="">116380</c-> <c- n="">ns</c->            <c- mi="">5</c->
</pre>
      <p>With N=1000 (<code class="highlight"><c- n="">Matt</c-></code> can’t
        handle this because <code class="highlight"><c- n="">h</c-><c- p="">.</c-><c-

            n="">block_capacity_hard_limits</c-><c- p="">().</c-><c- n="">max</c->
          <c- o="">&lt;</c-> <c- mi="">1000</c-></code>), again no significant
        difference:</p>
      <pre class="nohighlight highlight"><c- n="">$</c-> <c- n="">bin</c-><c- o="">/</c-><c-

n="">ubench</c-> <c- o="">--</c-><c- n="">benchmark_display_aggregates_only</c-><c-

o="">=</c->true <c- o="">--</c-><c- n="">benchmark_repetitions</c-><c- o="">=</c-><c-

mi="">5</c-> <c- o="">|</c-> <c- n="">grep</c-> <c- n="">mean</c->
<c- mi="">2022</c-><c- mo="">-06</c-><c- mi="">-10</c-><c- n="">T00</c-><c- o="">:</c-><c-

mi="">33</c-><c- o="">:</c-><c- mi="">12</c-><c- mo="">-04</c-><c- o="">:</c-><c-

mo="">00</c->
<c- n="">Running</c-> <c- n="">bin</c-><c- o="">/</c-><c- n="">ubench</c->
<c- n="">Run</c-> <c- n="">on</c-> <c- p="">(</c-><c- mi="">8</c-> <c- n="">X</c-> <c-

mi="">2200</c-> <c- n="">MHz</c-> <c- n="">CPU</c-> <c- n="">s</c-><c- p="">)</c->
<c- n="">CPU</c-> <c- n="">Caches</c-><c- o="">:</c->
  <c- n="">L1</c-> <c- n="">Data</c-> <c- mi="">32</c-> <c- n="">KiB</c-> <c- p="">(</c-><c-

n="">x4</c-><c- p="">)</c->
  <c- n="">L1</c-> <c- n="">Instruction</c-> <c- mi="">32</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x4</c-><c- p="">)</c->
  <c- n="">L2</c-> <c- n="">Unified</c-> <c- mi="">256</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x4</c-><c- p="">)</c->
  <c- n="">L3</c-> <c- n="">Unified</c-> <c- mi="">6144</c-> <c- n="">KiB</c-> <c-

p="">(</c-><c- n="">x1</c-><c- p="">)</c->
<c- n="">Load</c-> <c- n="">Average</c-><c- o="">:</c-> <c- mf="">2.13</c-><c- p="">,</c-> <c-

mf="">2.17</c-><c- p="">,</c-> <c- mf="">2.08</c->
<c- n="">BM_PlfStackIssue1_OldSmart_mean</c->       <c- mi="">973149</c-> <c- n="">ns</c->       <c-

mi="">972004</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_OldNaive_mean</c->       <c- mi="">970737</c-> <c- n="">ns</c->       <c-

mi="">969565</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_NewSmart_mean</c->      <c- mi="">1032303</c-> <c- n="">ns</c->      <c-

mi="">1031035</c-> <c- n="">ns</c->            <c- mi="">5</c->
<c- n="">BM_PlfStackIssue1_NewNaive_mean</c->      <c- mi="">1011931</c-> <c- n="">ns</c->      <c-

mi="">1010680</c-> <c- n="">ns</c->            <c- mi="">5</c->
</pre>
      <p style="color: red"><strong>Matt:
          These micro-benchmarks do not take into account
          the usage patterns of the container. In the benchmarks which I did regarding
          maximum block capacity limits, that were explained in detail on
          the LEWG reflector, there were no performance advantages to maximum
          block capacities greater than 16384 elements, only greater memory
          waste. There is a lot wrong with the above. But
          all the information required to understand performance related to block
          capacities is already publicly available on the reflector, and this data is what
          informed the removal of the hive priority template parameter in the first place.<br>
          See: Re: [isocpp-lib-ext] Is hive priority worth the cost? (Matt
          Bentley, Sun, Apr 10, 2022 at 8:51 PM) (<a href="https://lists.isocpp.org/lib-ext/2022/04/22987.php">https://lists.isocpp.org/lib-ext/2022/04/22987.php</a>)</strong></p>

      <h2 style="color: red" class="heading settled" data-level="4">Matt: SUMMARY</h2>
      <h3 style="color: red">Points in favour of retaining status quo:</h3><br>
        <ol style="color: blue">
		  <li>The library/implementation doesn't know the cache-line size, and
        users may want their element blocks to be multiples of cache-line
        capacity in order to improve read locality.</li>
        <li>The library/implementation doesn't know the user's erasure/insertion
        patterns for their data, and the efficiency of hive traversal and memory waste associated
        with that is affected by block capacities. eg. Users inserting/erasing in
        fixed amounts would likely want blocks that match that amount (or
        multiples of that amount).</li>
        <li>Bigger max block capacity != better, due to erasures. Blocks are removed from the iterative
        sequence once empty of non-erased elements, and with a high erasure
        percentage you will end up with more gaps between elements, and more wasted
        memory, statistically-speaking, the larger your block capacity is. Gaps between elements affect cache locality during iteration and performance. And the memory waste can hit embedded and high-performance devs hard.</li>
        <li>Bigger max block capacity != better, due to
        cache limits. Once your block is &gt;= the size of your cache
        line, you don't get any greater locality, only fewer
        allocations/deallocations upon insertion/erasure. This is confirmed in the benchmarks mentioned earlier.</li>
        <li>Maximum block capacities are necessary to prevent over-allocation.
        This is already a problem we have with vector. Particularly for
        high-memory-demand environments like game engines and the like, not
        being able to control the size of the next allocation is not an option.</li>
        <li>Some allocators may only allocate in specific chunks, and this
        feature aids that (although the user would need to look at the container
        code to figure out the total amount of allocation, unless we add in the
        function (from colony) to do it for them).</li>
        <li>We cannot necessarily anticipate all user needs and should aim for more flexibility of usage within reason, not less.</li>
        <li>Some users may wish to use hive for SIMD processing, the usage of
        which is explained earlier.</li>
        <li>Blocks limits are always going to be in an implementation regardless of whether a user specifies them. On the minimum side it makes sense to have a reasonable minimum which isn't lower in size than the amount of memory used for that first block's metadata.
        On the maximum side this is determined (in this implementation) by the bit-depth of the jump-counting skipfield. A 16-bit skipfield means a maximum jump of 65535 elements within the block, so the <i>hard</i> max block limit becomes 65536 (note: if a skip goes further than the block, a separate skip is recorded at the start of the next block). Higher bit-depths waste memory and do not perform better, for many reasons (including points 3 &amp; 4 above). So the extra code to support user block limits is nearly incidental.</li>
        <li>This is the one feature which actual users have repeatedly
        thanked me for because they find it useful. It is quite bizarre to me that someone would choose to remove it on grounds of technical personal aesthetics.</li>
        </ol>
        <br>
        <h3 style="color: red">Points in favour of removing this feature (which have not been
          proven false):</h3><br>
          <ol style="color: blue">
        <li>None of the other containers have it - well, deque and vector have
        capacity, but list doesn't. map and set have keys, but vector, deque and
        list don't. List has splice and none of the others have it. Hive has
        capacity limits, and none of the others have it.</li>
        <li>The presense of limits increases the number of constructors - but, all of those
        additional overloads are achievable via delegation, so there is no code
        bloat.</li>
        <li>Increases implementation load - as mentioned the increase is barely anything. All the Actual work goes into the specifics of the container and the three core design aspects. Since two major
        vendors have stated they'll likely fork the reference implementation, and the other is likely to use it as a reference, the
        minimal additional load is <em>already done</em>.</li>
        </ol>

        <p >This paper has been a waste of committee time, my time, and has served no-one. I would like you to dismiss it - Matt</p>
  </body>
</html>