<!doctype html><html lang="en">
 <head>
  <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
  <meta content="width=device-width, initial-scale=1, shrink-to-fit=no" name="viewport">
  <title>P1053R1: Future-proofing continuations for executors</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
 *
 * 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)
 *   - .assertion  for assertions                    (div, p, span)
 *   - .advisement for loud normative statements     (div, p, strong)
 *   - .annoying-warning for spec obsoletion notices (div, aside, details)
 *
 * 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
 *
 * 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)
 *
 ******************************************************************************/

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

	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;

		/* Colors */
		color: black;
		background: white 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-width: .65rem .7rem .6rem;
		border-radius: .4rem;
		background: #1a5e9a;
		color: white;
		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;
		border-color: #c00;
	}

	/* 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: 2;
			bottom: 0; left: 0;
			margin: 0;
			min-width: 1.33em;
			border-top-right-radius: 2rem;
			box-shadow: 0 0 2px;
			font-size: 1.5em;
			color: black;
		}
		#toc-nav > a {
			display: block;
			white-space: nowrap;

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

			background: white;
			box-shadow: 0 0 2px;
			border: none;
			border-top-right-radius: 1.33em;
			background: white;
		}
		#toc-nav > #toc-jump {
			padding-bottom: 2em;
			margin-bottom: -1.9em;
		}

		#toc-nav > a:hover,
		#toc-nav > a:focus {
			background: #f8f8f8;
		}
		#toc-nav > a:not(:hover):not(:focus) {
			color: #707070;
		}

		/* 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-toggle-inline {
			vertical-align: 0.05em;
			font-size: 80%;
			color: gray;
			color: hsla(203,20%,40%,.7);
			border-style: none;
			background: transparent;
			position: relative;
		}
		#toc-toggle-inline:hover:not(:active),
		#toc-toggle-inline:focus:not(:active) {
			text-shadow: 1px 1px silver;
			top: -1px;
			left: -1px;
		}

		#toc-nav :active {
			color: #C00;
		}
	}

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

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

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

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

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

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

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

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

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

	h1, h2, h3 {
		color: #005A9C;
		background: transparent;
	}

	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,
	#subtitle {
		/* #subtitle 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) > hr {
		font-size: 1.5em;
		text-align: center;
		margin: 1em auto;
		height: auto;
		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;
	}

	/* Put nice boxes around each algorithm. */
	[data-algorithm]:not(.heading) {
	  padding: .5em;
	  border: thin solid #ddd; 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: medium;
	}
	dfn var {
		font-style: normal;
	}

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

	del { color: red;  text-decoration: line-through; }
	ins { color: #080; text-decoration: underline;    }

/** 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;
		page-break-inside: avoid;
		hyphens: none;
		text-transform: none;
	}
	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;
		text-decoration: none;
		border-bottom: 1px solid #707070;
		/* Need a bit of extending for it to look okay */
		padding: 0 1px 0;
		margin: 0 -1px 0;
	}
	a:visited {
		border-bottom-color: #BBB;
	}

	/* Use distinguishing colors when user is interacting with the link */
	a[href]:focus,
	a[href]:hover {
		background: #f8f8f8;
		background: rgba(75%, 75%, 75%, .25);
		border-bottom-width: 3px;
		margin-bottom: -2px;
	}
	a[href]:active {
		color: #C00;
		border-color: #C00;
	}

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

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

	img {
		border-style: none;
	}

	/* 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;
	}
	.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 {
		padding: .5em;
		border: .5em;
		border-left-style: solid;
		page-break-inside: avoid;
	}
	span.issue, span.note {
		padding: .1em .5em .15em;
		border-right-style: solid;
	}

	.issue,
	.note,
	.example,
	.advisement,
	.assertion,
	blockquote {
		margin: 1em auto;
	}
	.note  > p:first-child,
	.issue > p:first-child,
	blockquote > :first-child {
		margin-top: 0;
	}
	blockquote > :last-child {
		margin-bottom: 0;
	}

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

	blockquote {
		border-color: silver;
	}

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

	.issue {
		border-color: #E05252;
		background: #FBE9E9;
		counter-increment: issue;
		overflow: auto;
	}
	.issue::before, .issue > .marker {
		text-transform: uppercase;
		color: #AE1E1E;
		padding-right: 1em;
		text-transform: uppercase;
	}
	/* 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;
		background: #FCFAEE;
		counter-increment: example;
		overflow: auto;
		clear: both;
	}
	.example::before, .example > .marker {
		text-transform: uppercase;
		color: #827017;
		min-width: 7.5em;
		display: block;
	}
	/* 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;
		background: #E9FBE9;
		overflow: auto;
	}

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

	details.note > summary {
		display: block;
		color: hsl(120, 70%, 30%);
	}
	details.note[open] > summary {
		border-bottom: 1px silver solid;
	}

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

	.assertion {
		border-color: #AAA;
		background: #EEE;
	}

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

	.advisement {
		border-color: orange;
		border-style: none solid;
		background: #FFEECC;
	}
	strong.advisement {
		display: block;
		text-align: center;
	}
	.advisement > .marker {
		color: #B35F00;
	}

/** 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: #fdd;
		color: red;
		font-weight: bold;
		padding: .75em 1em;
		border: thick red;
		border-style: solid;
		border-radius: 1em;
	}
	.annoying-warning :last-child {
		margin-bottom: 0;
	}

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

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

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

	.def {
		padding: .5em 1em;
		background: #DEF;
		margin: 1.2em 0;
		border-left: 0.5em solid #8CCBF2;
	}

/******************************************************************************/
/*                                    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;
	}

	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-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;
		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;
		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-top: 0.1rem;
		/* Larger, more consistently-sized click target */
		display: block;
		/* Reverse color scheme */
		color: black;
		border-color: #3980B5;
		border-bottom-width: 3px !important;
		margin-bottom: 0px !important;
	}
	.toc a:visited {
		border-color: #054572;
	}
	.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;
		line-height: 1.1rem; /* consistent spacing */
	}

	/* 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 .secno { font-size: 85%; }
	.toc > li li li li li { font-size:   85%;    }
	.toc > li li li li li .secno { font-size: 100%; }

	/* @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 {
			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; }
		}
	/* } */

	@supports (display:grid) {
		/* 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 .secno {
			grid-column: 1;
			width: auto;
		}
		#toc .content {
			grid-column: 2;
			width: auto;
			margin-right: 1rem;
		}
		#toc .content:hover {
			background: rgba(75%, 75%, 75%, .25);
			border-bottom: 3px solid #054572;
			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 span {
			white-space: nowrap;
			color: transparent; }
		ul.index li a:hover + span,
		ul.index li a:focus + span {
			color: #707070;
		}
	}

/** 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]) {
		background: #f7f8f9;
	}

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

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

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

/******************************************************************************/
/*                                    Legacy                                  */
/******************************************************************************/

	/* This rule is inherited from past style sheets. No idea what it's for. */
	.hide { display: none }



/******************************************************************************/
/*                             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 > table {
		/* limit preferred width of table */
		max-width: 50em;
		margin-left: auto;
		margin-right: auto;
	}

	@media (min-width: 55em) {
		.overlarge {
			margin-left: calc(13px + 26.5rem - 50vw);
			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-left: calc(40em - 50vw) !important;
			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-left: 0 !important;
			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 type="text/css">
    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;
    }
  </style>
  <meta content="Bikeshed version 6abc9f98f620481a5031cd9b44944d60af9b79b9" name="generator">
  <link href="https://wg21.link/P1053R1" rel="canonical">
  <link href="https://isocpp.org/favicon.ico" rel="icon">
<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-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-syntax-highlighting */

.highlight:not(.idl) { background: hsl(24, 20%, 95%); }
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 .c { color: #708090 } /* Comment */
.highlight .k { color: #990055 } /* Keyword */
.highlight .l { color: #000000 } /* Literal */
.highlight .n { color: #0077aa } /* Name */
.highlight .o { color: #999999 } /* Operator */
.highlight .p { color: #999999 } /* Punctuation */
.highlight .cm { color: #708090 } /* Comment.Multiline */
.highlight .cp { color: #708090 } /* Comment.Preproc */
.highlight .c1 { color: #708090 } /* Comment.Single */
.highlight .cs { color: #708090 } /* Comment.Special */
.highlight .kc { color: #990055 } /* Keyword.Constant */
.highlight .kd { color: #990055 } /* Keyword.Declaration */
.highlight .kn { color: #990055 } /* Keyword.Namespace */
.highlight .kp { color: #990055 } /* Keyword.Pseudo */
.highlight .kr { color: #990055 } /* Keyword.Reserved */
.highlight .kt { color: #990055 } /* Keyword.Type */
.highlight .ld { color: #000000 } /* Literal.Date */
.highlight .m { color: #000000 } /* Literal.Number */
.highlight .s { color: #a67f59 } /* Literal.String */
.highlight .na { color: #0077aa } /* Name.Attribute */
.highlight .nc { color: #0077aa } /* Name.Class */
.highlight .no { color: #0077aa } /* Name.Constant */
.highlight .nd { color: #0077aa } /* Name.Decorator */
.highlight .ni { color: #0077aa } /* Name.Entity */
.highlight .ne { color: #0077aa } /* Name.Exception */
.highlight .nf { color: #0077aa } /* Name.Function */
.highlight .nl { color: #0077aa } /* Name.Label */
.highlight .nn { color: #0077aa } /* Name.Namespace */
.highlight .py { color: #0077aa } /* Name.Property */
.highlight .nt { color: #669900 } /* Name.Tag */
.highlight .nv { color: #222222 } /* Name.Variable */
.highlight .ow { color: #999999 } /* Operator.Word */
.highlight .mb { color: #000000 } /* Literal.Number.Bin */
.highlight .mf { color: #000000 } /* Literal.Number.Float */
.highlight .mh { color: #000000 } /* Literal.Number.Hex */
.highlight .mi { color: #000000 } /* Literal.Number.Integer */
.highlight .mo { color: #000000 } /* Literal.Number.Oct */
.highlight .sb { color: #a67f59 } /* Literal.String.Backtick */
.highlight .sc { color: #a67f59 } /* Literal.String.Char */
.highlight .sd { color: #a67f59 } /* Literal.String.Doc */
.highlight .s2 { color: #a67f59 } /* Literal.String.Double */
.highlight .se { color: #a67f59 } /* Literal.String.Escape */
.highlight .sh { color: #a67f59 } /* Literal.String.Heredoc */
.highlight .si { color: #a67f59 } /* Literal.String.Interpol */
.highlight .sx { color: #a67f59 } /* Literal.String.Other */
.highlight .sr { color: #a67f59 } /* Literal.String.Regex */
.highlight .s1 { color: #a67f59 } /* Literal.String.Single */
.highlight .ss { color: #a67f59 } /* Literal.String.Symbol */
.highlight .vc { color: #0077aa } /* Name.Variable.Class */
.highlight .vg { color: #0077aa } /* Name.Variable.Global */
.highlight .vi { color: #0077aa } /* Name.Variable.Instance */
.highlight .il { color: #000000 } /* Literal.Number.Integer.Long */
</style>
<style>/* style-selflinks */

.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: gray;
    color: white;
    font-style: normal;
    transition: opacity .2s, background-color .2s, color .2s;
}
dfn:hover > a.self-link {
    opacity: 1;
}
dfn > a.self-link:hover {
    color: black;
}

a.self-link::before            { content: "¶"; }
.heading > a.self-link::before { content: "§"; }
dfn > a.self-link::before      { content: "#"; }</style>
<style>/* style-autolinks */

.css.css, .property.property, .descriptor.descriptor {
    color: #005a9c;
    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>
 <body class="h-entry">
  <div class="head">
   <p data-fill-with="logo"></p>
   <h1 class="p-name no-ref" id="title">P1053R1<br>Future-proofing continuations for executors</h1>
   <h2 class="no-num no-toc no-ref heading settled" id="subtitle"><span class="content">Published Proposal, <time class="dt-updated" datetime="2018-06-24">24 June 2018</time></span></h2>
   <div data-fill-with="spec-metadata">
    <dl>
     <dt>This version:
     <dd><a class="u-url" href="https://wg21.link/P1053R1">https://wg21.link/P1053R1</a>
     <dt>Authors:
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:lwh@fb.com">Lee Howes</a> (<span class="p-org org">Facebook</span>)
     <dd>
      <dd class="editor p-author h-card vcard"><a class="p-name fn u-email email" href="mailto:eniebler@fb.com">Eric Niebler</a> (<span class="p-org org">Facebook</span>)
     <dt>Audience:
     <dd>SG1, LEWG
     <dt>Project:
     <dd>ISO JTC1/SC22/WG21: Programming Language C++
     <dt>Source:
     <dd><a href="https://github.com/LeeHowes/CPP/blob/master/future_continuation.bs">https://github.com/LeeHowes/CPP/blob/master/future_continuations.bs</a>
    </dl>
   </div>
   <div data-fill-with="warning"></div>
   <hr title="Separator for header">
  </div>
  <nav data-fill-with="table-of-contents" id="toc">
   <h2 class="no-num no-toc no-ref" id="contents">Table of Contents</h2>
   <ol class="toc" role="directory">
    <li>
     <a href="#changelog"><span class="secno">1</span> <span class="content">Changelog</span></a>
     <ol class="toc">
      <li><a href="#revision1"><span class="secno">1.1</span> <span class="content">Revision 1</span></a>
      <li><a href="#revision0"><span class="secno">1.2</span> <span class="content">Revision 0</span></a>
     </ol>
    <li><a href="#intro"><span class="secno">2</span> <span class="content">Introduction and TLDR</span></a>
    <li>
     <a href="#require"><span class="secno">3</span> <span class="content">Requirements</span></a>
     <ol class="toc">
      <li><a href="#helper_thenvalue"><span class="secno">3.1</span> <span class="content">on_value</span></a>
      <li><a href="#helper_thenerror"><span class="secno">3.2</span> <span class="content">on_error</span></a>
      <li><a href="#helper_thenvariant"><span class="secno">3.3</span> <span class="content">on_variant</span></a>
      <li><a href="#helper_thenexceptionfilter"><span class="secno">3.4</span> <span class="content">on_value_with_exception_log</span></a>
     </ol>
    <li><a href="#concept"><span class="secno">4</span> <span class="content">Concept</span></a>
    <li>
     <a href="#examples"><span class="secno">5</span> <span class="content">Examples</span></a>
     <ol class="toc">
      <li><a href="#thenvalue_example"><span class="secno">5.1</span> <span class="content">on_value</span></a>
      <li><a href="#thenerror_example"><span class="secno">5.2</span> <span class="content">on_error</span></a>
      <li><a href="#thenvariant_example"><span class="secno">5.3</span> <span class="content">on_variant</span></a>
      <li><a href="#thenvalueloggingerror_example"><span class="secno">5.4</span> <span class="content">on_value_logging_error</span></a>
     </ol>
    <li><a href="#noexcept"><span class="secno">6</span> <span class="content">Noexcept</span></a>
    <li>
     <a href="#bulk"><span class="secno">7</span> <span class="content">Rethinking bulk execution</span></a>
     <ol class="toc">
      <li><a href="#p0443bulk"><span class="secno">7.1</span> <span class="content">Bulk as in P0443</span></a>
      <li><a href="#an-opportunity-rethinking-the-bulk-parameterisation"><span class="secno">7.2</span> <span class="content">An opportunity: rethinking the bulk parameterisation</span></a>
     </ol>
    <li>
     <a href="#wording"><span class="secno">8</span> <span class="content">Proposed New Wording for P0443</span></a>
     <ol class="toc">
      <li><a href="#promiserequire"><span class="secno">8.1</span> <span class="content"><code class="highlight"><span class="n">Promise</span></code> requirements</span></a>
      <li><a href="#onewayrequire"><span class="secno">8.2</span> <span class="content">OneWayFutureContinuation requirements</span></a>
      <li><a href="#twowayrequire"><span class="secno">8.3</span> <span class="content">TwoWayFutureContinuation requirements</span></a>
      <li><a href="#thenrequire"><span class="secno">8.4</span> <span class="content">ThenFutureContinuation requirements</span></a>
      <li><a href="#onewaychanges"><span class="secno">8.5</span> <span class="content">Changes to OneWayExecutor requirements</span></a>
      <li><a href="#twowaychanges"><span class="secno">8.6</span> <span class="content">Changes to TwoWayExecutor requirements</span></a>
      <li><a href="#thenchanges"><span class="secno">8.7</span> <span class="content">Changes to ThenExecutor requirements</span></a>
      <li><a href="#bulkchanges"><span class="secno">8.8</span> <span class="content">Changes to Bulk requirements in general</span></a>
     </ol>
   </ol>
  </nav>
  <main>
   <p>Contributors:</p>
   <ul>
    <li data-md="">
     <p>Jay      Feldblum</p>
    <li data-md="">
     <p>Andrii   Grynenko</p>
    <li data-md="">
     <p>Kirk     Shoop</p>
   </ul>
   <h2 class="heading settled" data-level="1" id="changelog"><span class="secno">1. </span><span class="content">Changelog</span><a class="self-link" href="#changelog"></a></h2>
   <h3 class="heading settled" data-level="1.1" id="revision1"><span class="secno">1.1. </span><span class="content">Revision 1</span><a class="self-link" href="#revision1"></a></h3>
   <ul>
    <li data-md="">
     <p>Added a before/after comparison.</p>
    <li data-md="">
     <p>Added TLDR to introduction.</p>
    <li data-md="">
     <p>Added concrete bulk design.</p>
    <li data-md="">
     <p>Proposed a more flexible bulk interface.</p>
    <li data-md="">
     <p>then_value -> on_value for consistency with <a href="https://wg21.link/P1054">p1054</a>.</p>
   </ul>
   <h3 class="heading settled" data-level="1.2" id="revision0"><span class="secno">1.2. </span><span class="content">Revision 0</span><a class="self-link" href="#revision0"></a></h3>
   <ul>
    <li data-md="">
     <p>Initial design</p>
   </ul>
   <h2 class="heading settled" data-level="2" id="intro"><span class="secno">2. </span><span class="content">Introduction and TLDR</span><a class="self-link" href="#intro"></a></h2>
    <a href="https://wg21.link/P0443">p0443</a> defines interfaces for executors and the
continuation functions passed to them. <a href="https://wg21.link/P1054">p1054</a> utilises these fundamental interfaces to build
expressive concepts for future types where continuations are cleanly mapped
through continuation construction functions. 
   <p>The current design of the continuation functions passed to then_execute are
based on the ability of the executor to invoke the continuation.</p>
   <p>In essence the continuations have an interface similar to:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="n">R</span> <span class="k">operator</span><span class="p">()(</span><span class="n">T</span><span class="p">);</span>
  <span class="n">R</span> <span class="nf">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">};</span>
</pre>
   <p>where either function is optional, and in that situation the other operation will act as a passthrough.
One reason for designing the API in this way is to allow a simple lambda function to be passed to <code class="highlight"><span class="n">then_execute</span></code>:</p>
<pre class="highlight"><span class="n">e</span><span class="p">.</span><span class="n">then_execute</span><span class="p">([](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="k">return</span> <span class="n">value</span><span class="p">;},</span> <span class="n">input_future</span><span class="p">);</span>
</pre>
   <p>The downsides of this design are twofold:</p>
   <ul>
    <li data-md="">
     <p>The description of the continuation is based on ability to invoke it. There is then potential for errors that would easily slip through code review, and silently cause unexpected runtime behaviour.</p>
    <li data-md="">
     <p>The mechanism of describing the continuation with two parallel end-to-end data paths removes the ability to catch and pass an exception from the value operator, or to log and passthrough an exception from the exception operator without rethrowing the exception.</p>
   </ul>
   <p>On the first point, consider the following struct that an author might write in an attempt to handle both values and exceptions at some stage in the pipeline:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>This is a trivial example of ignoring the precise exception and attempting to recover.
Note that the reality here, based on the <a href="https://wg21.link/P0443">p0443</a> definition is that the exception function is not callable as the <code class="highlight"><span class="n">EXCEPTIONAL</span></code> case.
It will therefore not be called and an exception will bypass.
In effect, this struct is semantically equivalent to:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>where we have silently lost our recovery path and passed the error through with potentially negative consequences.
There is no compilation or runtime error here, and this kind of problem could be hard to catch in code review.</p>
   <p>On the second point, consider an exception handler that only exists to log that an exception reached a point in the stream:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>This is an expensive means of doing nothing to the exception.
With potential extensions to <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> that would allow peeking at
the exception without rethrow, for example <a href="https://wg21.link/P1066">p1066</a>,
there is potentially a wide range of optimisations that we lose the ability to
perform.</p>
   <p>What we might prefer, would be to implement this as:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">callable</span> <span class="p">{</span>
  <span class="kt">int</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">value</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
  <span class="p">}</span>
  <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="k">operator</span><span class="p">()(</span><span class="n">exception_arg</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
    <span class="k">return</span> <span class="n">e</span><span class="p">;</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>but then we lose the ability to recreate the value.</p>
   <p>We consider these two flaws, one of safety and the other of flexibility, as
unfortunate limitations of a low-level API like executors.</p>
   <p>Expected use of <code class="highlight"><span class="n">FutureContinuation</span></code> as discussed in <a href="https://wg21.link/P1054">p1054</a> is
through the use of helper functions such as <code class="highlight"><span class="n">on_value</span></code> and <code class="highlight"><span class="n">on_error</span></code> that take
a constrained callable and return a <code class="highlight"><span class="n">FutureContinuation</span></code>.
With these helper functions, and the clean readable code they lead to, there is
no need to simplify the <code class="highlight"><span class="n">FutureContinuation</span></code> to be a trivial callable, and we
gain a lot of flexibility by consciously deciding to not simplify it in that
way.</p>
   <p>We propose to  solidify the <code class="highlight"><span class="n">FutureContinuation</span></code> definition into a more
fundamental and general task interface, without overload-resolution
complexities. Rather than passing simple callables into the executor and future
APIs, we propose a concrete continuation concept, based on promises. The API of
a continuation, from the point of view of the input data, is:</p>
<pre class="highlight"><span class="kt">void</span> <span class="nf">set_value</span><span class="p">();</span>
<span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">T</span><span class="o">></span>
<span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;&amp;</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">&amp;&amp;</span><span class="p">);</span>
</pre>
   <p>Bulk is also supported, but orthogonally to that fundamental data transfer API,
which allows bulk tasks to be passed through higher-level dataflow-oriented
abstractions such as futures..</p>
   <p>Syntactically, this proposal suggests only minor changes, and so usability for
any direct user of executors is minimally affected:</p>
   <table>
    <tbody>
     <tr>
      <th>Comment
      <th>Before
      <th>After
     <tr>
      <td>One way
      <td>
<pre class="highlight"><span class="n">executor</span><span class="p">.</span><span class="n">execute</span><span class="p">([](){</span><span class="n">task</span><span class="p">();});</span>
</pre>
      <td>
<pre class="highlight"><span class="n">executor</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span>
 <span class="n">on_value</span><span class="p">([](){</span>
  <span class="n">task</span><span class="p">();</span>
 <span class="p">}));</span>
</pre>
     <tr>
      <td>Bulk one way
      <td>
<pre class="highlight"><span class="n">executor</span><span class="p">.</span><span class="n">bulk_execute</span><span class="p">(</span>
 <span class="p">[</span><span class="o">&amp;</span><span class="n">out</span><span class="p">](</span>
   <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span>
   <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
  <span class="n">out</span><span class="o">+=</span><span class="n">idx</span> <span class="o">*</span> <span class="n">shr</span><span class="p">;</span>
 <span class="p">},</span>
 <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">3</span><span class="p">;});</span>
</pre>
      <td>
<pre class="highlight"><span class="n">executor</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span>
 <span class="n">bulk_on_value</span><span class="p">(</span>
  <span class="p">[</span><span class="o">&amp;</span><span class="n">out</span><span class="p">](</span>
   <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span>
   <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
  <span class="n">out</span><span class="o">+=</span><span class="n">idx</span> <span class="o">*</span> <span class="n">shr</span><span class="p">;</span>
 <span class="p">},</span>
 <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span> <span class="c1">// Shape</span>
<span class="c1"></span> <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">3</span><span class="p">;}));</span>
</pre>
     <tr>
      <td>Two way
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">twoway_execute</span><span class="p">(</span>
 <span class="p">[](){</span><span class="k">return</span> <span class="n">task</span><span class="p">();});</span>
</pre>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">twoway_execute</span><span class="p">(</span>
 <span class="n">on_value</span><span class="p">([](){</span>
  <span class="k">return</span> <span class="n">task</span><span class="p">();</span>
 <span class="p">}));</span>
</pre>
     <tr>
      <td>Bulk two way
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span>
  <span class="n">executor</span><span class="p">.</span><span class="n">bulk_twoway_execute</span><span class="p">([](</span>
   <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span>
   <span class="kt">int</span><span class="o">&amp;</span> <span class="n">out</span><span class="p">,</span>
   <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
  <span class="n">out</span><span class="o">+=</span><span class="n">idx</span><span class="o">*</span><span class="n">shr</span><span class="p">;</span>
 <span class="p">},</span>
 <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;},</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">3</span><span class="p">;});</span>
</pre>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">twoway_execute</span><span class="p">(</span>
 <span class="n">bulk_on_value</span><span class="p">(</span>
 <span class="p">[](</span>
   <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span>
   <span class="kt">int</span> <span class="o">&amp;</span><span class="n">out</span><span class="p">,</span>
   <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
  <span class="n">out</span><span class="o">+=</span><span class="n">idx</span><span class="o">*</span><span class="n">shr</span><span class="p">;</span>
 <span class="p">},</span>
 <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span> <span class="c1">// Shape</span>
<span class="c1"></span> <span class="p">[]()</span> <span class="o">-></span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;},</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">3</span><span class="p">;}));</span>
</pre>
     <tr>
      <td>Then
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">then_execute</span><span class="p">(</span>
 <span class="p">[](</span><span class="n">T</span> <span class="n">t</span><span class="p">){</span><span class="k">return</span> <span class="n">t</span><span class="p">;},</span>
 <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fut</span><span class="p">));</span>
</pre>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">then_execute</span><span class="p">(</span>
 <span class="n">on_value</span><span class="p">([](</span><span class="k">auto</span> <span class="n">t</span><span class="p">){</span>
  <span class="k">return</span> <span class="n">t</span><span class="p">;</span>
 <span class="p">}),</span>
 <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fut</span><span class="p">));</span>
</pre>
     <tr>
      <td>Bulk
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span>
 <span class="n">executor</span><span class="p">.</span><span class="n">bulk_then_execute</span><span class="p">([](</span>
   <span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">in</span><span class="p">,</span>
   <span class="kt">int</span> <span class="n">idx</span><span class="p">,</span>
   <span class="kt">int</span><span class="o">&amp;</span> <span class="n">out</span><span class="p">,</span>
   <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
  <span class="n">out</span><span class="o">+=</span><span class="n">in</span><span class="o">*</span><span class="p">(</span><span class="n">idx</span><span class="o">+</span><span class="n">shr</span><span class="p">);</span>
 <span class="p">},</span>
 <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span>
 <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fut</span><span class="p">),</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;},</span>
 <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">3</span><span class="p">;});</span>
</pre>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">executor</span><span class="p">.</span><span class="n">then_execute</span><span class="p">(</span>
 <span class="n">bulk_on_value</span><span class="p">(</span>
  <span class="p">[](</span>
    <span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">in</span><span class="p">,</span>
    <span class="kt">int</span> <span class="cm">/*idx*/</span><span class="p">,</span>
    <span class="kt">int</span> <span class="o">&amp;</span><span class="n">out</span><span class="p">,</span>
    <span class="kt">long</span><span class="o">&amp;</span> <span class="n">shr</span><span class="p">){</span>
   <span class="n">out</span><span class="o">+=</span><span class="n">in</span><span class="o">*</span><span class="p">(</span><span class="n">idx</span><span class="o">+</span><span class="n">shr</span><span class="p">);</span>
  <span class="p">},</span>
  <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span> <span class="c1">// Shape</span>
<span class="c1"></span>  <span class="p">[]()</span> <span class="o">-></span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;},</span>
  <span class="p">[]()</span> <span class="o">-></span> <span class="kt">long</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;}),</span>
 <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fut</span><span class="p">));</span>
</pre>
   </table>
   <p>Future’s continuation methods would be similarly modified to take the same
continuation concepts, which pass directly down to executors. For example:</p>
   <table>
    <tbody>
     <tr>
      <th>Before
      <th>After
     <tr>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">makeFuture</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">></span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  <span class="p">.</span><span class="n">via</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
  <span class="p">.</span><span class="n">then</span><span class="p">([](</span><span class="kt">int</span> <span class="n">a</span><span class="p">){</span><span class="k">return</span> <span class="n">a</span><span class="p">;});</span>
</pre>
      <td>
<pre class="highlight"><span class="k">auto</span> <span class="n">f</span> <span class="o">=</span> <span class="n">makeFuture</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">></span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
  <span class="o">|</span> <span class="n">via</span><span class="p">(</span><span class="n">e</span><span class="p">)</span>
  <span class="o">|</span> <span class="n">on_value</span><span class="p">([](</span><span class="kt">int</span> <span class="n">a</span><span class="p">){</span><span class="k">return</span> <span class="n">a</span><span class="p">;});</span>
</pre>
   </table>
   <p>Note that futures do not have to be expanded to support bulk explicitly, nor
for any similar future concepts we add beyond bulk. This should lead to simpler
expansions of the design in the future.</p>
   <p>The same modifications we propose in this paper apply to both <a href="https://wg21.link/P0443">p0443</a> and <a href="https://wg21.link/P1054">p1054</a>.
Uses of the types in <a href="https://wg21.link/P1054">p1054</a> are unaffected but the
description of the calling mechanism, return values of the construction
functions (<code class="highlight"><span class="n">on_value</span></code>, <code class="highlight"><span class="n">on_error</span></code>) and precise semantics would require updates
similar to those we propose for <a href="https://wg21.link/P0443">p0443</a>.</p>
   <p>The rest of this paper aims to justify the above design by explaining how we
derive it, followed by concrete proposed wording.</p>
   <h2 class="heading settled" data-level="3" id="require"><span class="secno">3. </span><span class="content">Requirements</span><a class="self-link" href="#require"></a></h2>
    If we look at some example continuation constructions based on those in <a href="https://wg21.link/P1054">p1054</a> we can see what kind of functionality we might
want here. 
   <h3 class="heading settled" data-level="3.1" id="helper_thenvalue"><span class="secno">3.1. </span><span class="content">on_value</span><a class="self-link" href="#helper_thenvalue"></a></h3>
    This is the simple passthrough of the exception, while applying some operation
to the value. 
   <p>The callback we expect to create looks like:</p>
<pre class="highlight"><span class="n">on_value</span><span class="p">([](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">value</span><span class="p">);});</span>
</pre>
   <p>As a flow diagram, something like:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">---------</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">return_value</span>

<span class="n">set_exception</span> <span class="o">-----------------------------</span> <span class="n">return_exception</span>
</pre>
   <h3 class="heading settled" data-level="3.2" id="helper_thenerror"><span class="secno">3.2. </span><span class="content">on_error</span><a class="self-link" href="#helper_thenerror"></a></h3>
    The equivalent where we apply some operation to the exception, but not the value.
A good example of this might be error recovery. Note that in this case we are breaking the exception chain.
The callback we expect to create looks like: 
<pre class="highlight"><span class="n">on_error</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span>
  <span class="k">try</span> <span class="p">{</span>
   <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">e</span><span class="p">);</span>
  <span class="p">}</span> <span class="k">catch</span><span class="p">(</span><span class="n">recoverable_exception</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
  <span class="p">}</span> <span class="k">catch</span><span class="p">(...)</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">rethrow_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
  <span class="p">}});</span>
</pre>
   <p>Or:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">-------------------------------------------------------/-----</span> <span class="n">return_value</span>
                                            <span class="o">/-----</span> <span class="n">Recover</span> <span class="o">-----/</span>
<span class="n">set_exception</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="o">|</span>
                                            \<span class="o">-----</span> <span class="n">Do</span> <span class="n">not</span> <span class="n">recover</span> <span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>Note that in this case we rethrow twice. Logically the first is just to check
the exception type. The second is just returning the exception and relying on
external logic to catch as we do not have two outputs in the syntax.
Improvements to <code class="highlight"><span class="n">exception_ptr</span></code> (along the lines of folly’s <a href="https://github.com/facebook/folly/blob/master/folly/ExceptionWrapper.h">exception_wrapper</a> or those proposed in <a href="https://wg21.link/P1066">p1066</a>) could mitigate the first.
Ability to return either an <code class="highlight"><span class="n">exception_ptr</span></code> or a <code class="highlight"><span class="n">T</span></code> from the error case could
remove the second throw.</p>
   <h3 class="heading settled" data-level="3.3" id="helper_thenvariant"><span class="secno">3.3. </span><span class="content">on_variant</span><a class="self-link" href="#helper_thenvariant"></a></h3>
    Here our operation might take a variant of a value and an exception so that we can write a single function that decides what to do:
The callback we expect to create looks like: 
<pre class="highlight"><span class="n">on_variant</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">v</span><span class="p">);});</span>
</pre>
   <p>Diagrammatically:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">-----</span>\                             <span class="o">/-----</span> <span class="n">return_value</span>
               <span class="o">|-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
<span class="n">set_exception</span> <span class="o">-/</span>                             \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>This is a very common pattern in Facebook’s code where <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">Try</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span></code>, which
carries a value and exception, is the preferred means of parameterising future
continuations.</p>
   <h3 class="heading settled" data-level="3.4" id="helper_thenexceptionfilter"><span class="secno">3.4. </span><span class="content">on_value_with_exception_log</span><a class="self-link" href="#helper_thenexceptionfilter"></a></h3>
    Here we merely log the existence of an error, and pass it through.
We might write this as: 
<pre class="highlight"><span class="n">on_value_with_exception_log</span><span class="p">(</span>
  <span class="p">[](</span><span class="n">T</span> <span class="n">value</span><span class="p">){</span><span class="n">operation</span><span class="p">(</span><span class="n">v</span><span class="p">);},</span>
  <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span><span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have an exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Here we have a very simple pair of parallel operations:</p>
<pre class="highlight"><span class="n">set_value</span> <span class="o">---------</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">return_value</span>

<span class="n">set_exception</span> <span class="o">-----</span> <span class="n">Log</span> <span class="o">-------------------</span> <span class="n">return_exception</span>
</pre>
   Note though that it relies on allowing return of an <code class="highlight"><span class="n">exception_ptr</span></code> from the
exception path to do this without a throw. 
   <h2 class="heading settled" data-level="4" id="concept"><span class="secno">4. </span><span class="content">Concept</span><a class="self-link" href="#concept"></a></h2>
    As an alternative way of thinking about this problem we should step back and think about what we want from the solution.
Fundamentally, a continuation is a function from a value input or an exceptional input, to a value output or an exceptional output. 
<pre class="highlight"><span class="n">set_value</span> <span class="o">-----</span>\                             <span class="o">/-----</span> <span class="n">return_value</span>
               <span class="o">|-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
<span class="n">set_exception</span> <span class="o">-/</span>                             \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>This basic structure covers all of the above uses. The question becomes how we can build this in an efficient manner?</p>
   <p>One option is to do what we do in a lot of Facebook’s code, and implement the operation in terms of <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">Try</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span></code> putting all functionality in the continuation itself.
Unfortunately, it is clumsy to write efficient code that wants to ignore one or other path entirely using this structure. We are forced into the combined structure in the code.</p>
   <p>Abstractly, though, if we assume that these operations are inputs and outputs from some class, we see that the input is a <code class="highlight"><span class="n">Promise</span></code> type:</p>
<pre class="highlight">                                     <span class="o">/-----</span> <span class="n">return_value</span>
<span class="n">Promise</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----|</span>
                                     \<span class="o">-----</span> <span class="n">return_exception</span>
</pre>
   <p>Where a promise is a class concept consisting of two <code class="highlight"><span class="kt">void</span></code>-returning functions: <code class="highlight"><span class="n">set_value</span></code> and <code class="highlight"><span class="n">set_exception</span></code>.</p>
   <p>Taking a further look at this we realise that actually the output path is merely the input to another operation - one owned by the executor itself. So we see another <code class="highlight"><span class="n">Promise</span></code> lying in wait for us:</p>
<pre class="highlight"><span class="n">Promise</span> <span class="o">-----</span> <span class="n">Perform</span> <span class="n">Operation</span> <span class="o">-----</span> <span class="n">Promise</span>
</pre>
   <p>Fundamentally, then, each of the continuation constructors should produce
something that has a promise as input, and a promise as output, and where the
value and error operations can be mixed based on the implementation.
This is fully general. Moreover, by requiring that both of these functions be
provided and thus called by the implementation, it is also safe because the
compiler will fail if a function fails to compile.
The <code class="highlight"><span class="n">set_value</span></code> input can map to either the <code class="highlight"><span class="n">return_value</span></code> or <code class="highlight"><span class="n">return_exception</span></code> output, and similarly for the <code class="highlight"><span class="n">set_exception</span></code> input.</p>
   <p>So what does this look like? Because the Promises are both concepts, not types,
we need to be able to generate this code.
The input promise is a feature of the task we construct. This much is simple.
In addition, we need a way to take the output promise as an input. That is, we
need to construct a usable task from some partial task, plus a promise.</p>
   <p>In summary:</p>
   <blockquote>
    <p>The continuation is an object that, when passed a Promise as a parameter
constructs a new object that is itself a Promise.</p>
   </blockquote>
   <h2 class="heading settled" data-level="5" id="examples"><span class="secno">5. </span><span class="content">Examples</span><a class="self-link" href="#examples"></a></h2>
    Let’s take a few examples of what this looks like to implement. 
   <p>Given a continuation provided by some continuation construction function (some
examples of which we see below) and passed to our processing function, we can
use the continuation by:
 1) constructing internal <code class="highlight"><span class="n">Promise</span></code> that is tied to  our output <code class="highlight"><span class="n">Future</span></code> 2) pass the output promise to the continuation as a means of constructing a
       viable promise object.
 3) call the appropriate operation on the input with data from our input <code class="highlight"><span class="n">Future</span></code>.</p>
   <p>In code that general principle looks like:</p>
<pre class="highlight"><span class="n">OutputFuture</span> <span class="nf">process_continuation</span><span class="p">(</span><span class="n">FutureContinuation</span><span class="o">&amp;&amp;</span> <span class="n">continuation</span><span class="p">)</span> <span class="p">{</span>
  <span class="c1">// Construct output promise/future contract</span>
<span class="c1"></span>  <span class="p">[</span><span class="n">outputPromise</span><span class="p">,</span> <span class="n">outputFuture</span><span class="p">]</span> <span class="n">make_promise_contract</span><span class="o">&lt;</span><span class="n">T</span><span class="o">></span><span class="p">();</span>

  <span class="c1">// Construct the input promise by parameterising the continuation with the</span>
<span class="c1"></span>  <span class="c1">// output promise.</span>
<span class="c1"></span>  <span class="k">auto</span> <span class="n">inputPromise</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuation</span><span class="p">)(</span><span class="n">outputPromise</span><span class="p">);</span>

  <span class="c1">// Call the appropriate input data path on the input promise</span>
<span class="c1"></span>  <span class="k">if</span><span class="p">(</span><span class="n">have_value</span><span class="p">())</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputPromise</span><span class="p">).</span><span class="n">set_value</span><span class="p">(</span><span class="n">value</span><span class="p">());</span>
  <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputPromise</span><span class="p">).</span><span class="n">set_exception</span><span class="p">(</span><span class="n">exception</span><span class="p">());</span>
  <span class="p">}</span>

  <span class="c1">// Return the outputFuture that will include the result of the computation</span>
<span class="c1"></span>  <span class="k">return</span> <span class="n">outputFuture</span><span class="p">;</span>
<span class="p">}</span>
</pre>
   <h3 class="heading settled" data-level="5.1" id="thenvalue_example"><span class="secno">5.1. </span><span class="content">on_value</span><a class="self-link" href="#thenvalue_example"></a></h3>
    <code class="highlight"><span class="n">on_value</span></code> takes a function from a value to a value and, as discussed above,
returns a function that can be passed a Promise, and which constructs a Promise: 
<pre class="highlight"><span class="c1">// F = function(int(int))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">on_value</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>and constructs the continuation as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">on_value</span><span class="p">([](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="mi">2</span><span class="p">;});</span>
</pre>
   <p>As an example of using these constructs as if as a simple callback, for an
executor that only supports simple callback mechanisms, we can see that all of
this code optimises to nothing
(<a href="https://godbolt.org/g/m3qvoj">https://godbolt.org/g/m3qvoj</a>).</p>
   <h3 class="heading settled" data-level="5.2" id="thenerror_example"><span class="secno">5.2. </span><span class="content">on_error</span><a class="self-link" href="#thenerror_example"></a></h3>
    Here we construct a continuation from a function from exception_ptr to
exception_ptr as a means of only processing our error stream. 
<pre class="highlight"><span class="c1">// F = function(exception_ptr(exception_ptr))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">on_error</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
                    <span class="c1">// Set the exception from the return value</span>
<span class="c1"></span>                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="c1">// Also catch the error for completeness.</span>
<span class="c1"></span>                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>We can construct a simple exception processing continuation as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">on_error</span><span class="p">([](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Log!</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Note that even here, if we do not end up using the exception path, all of this
optimises away (<a href="https://godbolt.org/g/xRm2oH">https://godbolt.org/g/xRm2oH</a>)</p>
   <h3 class="heading settled" data-level="5.3" id="thenvariant_example"><span class="secno">5.3. </span><span class="content">on_variant</span><a class="self-link" href="#thenvariant_example"></a></h3>
    We can implement a version that passes variants through as: 
<pre class="highlight"><span class="c1">// F = function(variant&lt;int, exception_ptr>(variant&lt;int, exception_ptr>))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="o">></span>
<span class="k">auto</span> <span class="n">on_variant</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">apply</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">apply</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>

            <span class="kt">void</span> <span class="nf">apply</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">struct</span> <span class="n">visitor</span> <span class="p">{</span>
                    <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">result</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">result</span><span class="p">));</span>
                    <span class="p">}</span>
                    <span class="kt">void</span> <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">ex</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">ex</span><span class="p">));</span>
                    <span class="p">}</span>
                    <span class="n">OutputPromise</span><span class="o">&amp;</span> <span class="n">outputPromise_</span><span class="p">;</span>
                <span class="p">};</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">intermediateValue</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">v</span><span class="p">));</span>
                    <span class="n">std</span><span class="o">::</span><span class="n">visit</span><span class="p">(</span><span class="n">visitor</span><span class="p">{</span><span class="n">outputPromise_</span><span class="p">},</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">intermediateValue</span><span class="p">));</span>
                <span class="p">}</span> <span class="k">catch</span><span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>Constructing the continuation with:</p>
<pre class="highlight"><span class="k">struct</span> <span class="n">visitor</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span>
    <span class="k">operator</span><span class="p">()(</span><span class="kt">int</span> <span class="n">val</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">val</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span>
    <span class="k">operator</span><span class="p">()(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">ex</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
      <span class="k">return</span> <span class="n">ex</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">};</span>
<span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">on_variant</span><span class="p">(</span>
    <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="n">v</span><span class="p">)</span> <span class="o">-></span> <span class="n">std</span><span class="o">::</span><span class="n">variant</span><span class="o">&lt;</span><span class="kt">int</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="o">></span> <span class="p">{</span>
        <span class="k">return</span> <span class="n">std</span><span class="o">::</span><span class="n">visit</span><span class="p">(</span><span class="n">visitor</span><span class="p">{},</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">v</span><span class="p">));</span>
    <span class="p">});</span>
</pre>
   <p>Again, with use of variants, if we do not actually use the <code class="highlight"><span class="n">exception_ptr</span></code> route
this optimises away
(<a href="https://godbolt.org/g/AZRAeK">https://godbolt.org/g/AZRAeK</a>).</p>
   <h3 class="heading settled" data-level="5.4" id="thenvalueloggingerror_example"><span class="secno">5.4. </span><span class="content">on_value_logging_error</span><a class="self-link" href="#thenvalueloggingerror_example"></a></h3>
    Finally, we can build an operation that takes two functions, where the error
handler simply passes through the exception with logging: 
<pre class="highlight"><span class="c1">// F = function(int(int))</span>
<span class="c1"></span><span class="k">template</span> <span class="o">&lt;</span><span class="k">typename</span> <span class="n">F</span><span class="p">,</span> <span class="k">typename</span> <span class="n">FE</span><span class="o">></span>
<span class="k">auto</span> <span class="n">on_value_log_exception</span><span class="p">(</span><span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">valueContinuation</span><span class="p">,</span> <span class="n">FE</span><span class="o">&amp;&amp;</span> <span class="n">errorContinuation</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">return</span> <span class="p">[</span><span class="n">valueContinuation</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">valueContinuation</span><span class="p">),</span>
            <span class="n">errorContinuation</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">FE</span><span class="o">></span><span class="p">(</span><span class="n">errorContinuation</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
        <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
        <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

        <span class="k">class</span> <span class="nc">InputPromise</span> <span class="p">{</span>
        <span class="k">public</span><span class="o">:</span>
            <span class="n">InputPromise</span><span class="p">(</span>
                <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">f</span><span class="p">,</span> <span class="n">FE</span><span class="o">&amp;&amp;</span> <span class="n">fe</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="o">:</span>
                <span class="n">f_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">f</span><span class="p">)),</span> <span class="n">fe_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">fe</span><span class="p">)),</span> <span class="n">outputPromise_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">))</span> <span class="p">{}</span>

            <span class="kt">void</span> <span class="n">set_value</span><span class="p">(</span><span class="kt">int</span> <span class="n">value</span><span class="p">)</span> <span class="p">{</span>
                <span class="k">try</span> <span class="p">{</span>
                    <span class="k">auto</span> <span class="n">resultOfOperation</span> <span class="o">=</span> <span class="n">f_</span><span class="p">(</span><span class="n">value</span><span class="p">);</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">resultOfOperation</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">catch</span> <span class="p">(...)</span> <span class="p">{</span>
                    <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">current_exception</span><span class="p">());</span>
                <span class="p">}</span>
            <span class="p">}</span>

            <span class="kt">void</span> <span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
                <span class="n">outputPromise_</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">fe_</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">e</span><span class="p">)));</span>
            <span class="p">}</span>

        <span class="k">private</span><span class="o">:</span>
            <span class="n">F</span> <span class="n">f_</span><span class="p">;</span>
            <span class="n">FE</span> <span class="n">fe_</span><span class="p">;</span>
            <span class="n">OutputPromise</span> <span class="n">outputPromise_</span><span class="p">;</span>
        <span class="p">};</span>

        <span class="k">return</span> <span class="nf">InputPromise</span><span class="p">(</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">valueContinuation</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">errorContinuation</span><span class="p">),</span>
            <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">));</span>
    <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>and where we might construct this as:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">on_value_log_exception</span><span class="p">(</span>
    <span class="p">[](</span><span class="kt">int</span> <span class="n">x</span><span class="p">)</span> <span class="p">{</span><span class="k">return</span> <span class="n">x</span><span class="o">*</span><span class="mi">2</span><span class="p">;},</span>
    <span class="p">[](</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span> <span class="n">e</span><span class="p">){</span><span class="n">std</span><span class="o">::</span><span class="n">cerr</span> <span class="o">&lt;&lt;</span> <span class="s">"Have exception</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span> <span class="k">return</span> <span class="n">e</span><span class="p">;});</span>
</pre>
   <p>Note that with improvements to <code class="highlight"><span class="n">exception_ptr</span></code> this is where we could benefit
from snooping on the exception without rethrow, as <code class="highlight"><span class="n">folly</span><span class="o">::</span><span class="n">exception_wrapper</span></code> enables or is proposed in <a href="https://wg21.link/P1066">p1066</a>. Full source example: <a href="https://godbolt.org/g/Xbp5xK">https://godbolt.org/g/Xbp5xK</a>.</p>
   <h2 class="heading settled" data-level="6" id="noexcept"><span class="secno">6. </span><span class="content">Noexcept</span><a class="self-link" href="#noexcept"></a></h2>
   <p>The methods on <code class="highlight"><span class="n">FutureContinuation</span></code> should be noexcept.
Any exception handling should be handled as part of the <code class="highlight"><span class="n">FutureContinuation</span></code> task and passed to the <code class="highlight"><span class="n">set_exception</span></code> output.</p>
   <p>With this change, the executors do not need exception propagation properties,
nor do they need to expose queries that specify what happens when an exception
leaks from a continuation because this cannot happen. This is a considerable
simplification and reduction in committee work that is still in progress.</p>
   <h2 class="heading settled" data-level="7" id="bulk"><span class="secno">7. </span><span class="content">Rethinking bulk execution</span><a class="self-link" href="#bulk"></a></h2>
   <p>We should encode bulk operations as extended continuations.
Bulk execution is a property of a task, not an executor. While we realise that
the executor has influence on how the task runs and where, which may include
how it is compiled to do bulk dispatch, the actual properties of the task
are orthogonal to the API exposed by executors. To put it another way, the flow
of data through the graph is orthogonal to whether a given node in that graph
offers fork-join or other forms of execution.</p>
   <p>Encoding the bulk functionality as part of the continuation, rather than the
executor API, would allow us to halve the number of executor entry points.
Further, bulk continuations need not be part of the fundamental concepts and
instead we can encode the interface simply as an extended set of task
construction functions as in <a href="https://wg21.link/P1054">p1054</a>. It also means
we do not have to complicated the definition of Futures to add bulk APIs; the
task passed to a future can be transparently passed to the underlying executor
and the future does not care whether it is a bulk task or not.</p>
   <h3 class="heading settled" data-level="7.1" id="p0443bulk"><span class="secno">7.1. </span><span class="content">Bulk as in P0443</span><a class="self-link" href="#p0443bulk"></a></h3>
   <p>Abstracted as a task and used in the executor or future API, a bulk operation would look like the following:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">bulk_on_value</span><span class="p">(</span>
    <span class="p">[](</span>
        <span class="k">const</span> <span class="kt">int</span><span class="o">&amp;</span> <span class="n">input</span><span class="p">,</span>
        <span class="kt">int</span> <span class="cm">/*idx*/</span><span class="p">,</span>
        <span class="n">atomic</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">>&amp;</span> <span class="cm">/*shared*/</span><span class="p">,</span>
        <span class="kt">int</span> <span class="o">&amp;</span><span class="n">out</span><span class="p">){</span>
      <span class="n">out</span><span class="o">+=</span><span class="n">input</span><span class="p">;</span>
    <span class="p">},</span> <span class="c1">// Task</span>
<span class="c1"></span>    <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">},</span> <span class="c1">// Shape</span>
<span class="c1"></span>    <span class="p">[]()</span> <span class="o">-></span> <span class="n">atomic</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">></span> <span class="p">{</span><span class="k">return</span> <span class="p">{</span><span class="mi">0</span><span class="p">};},</span> <span class="c1">// Shared factory</span>
<span class="c1"></span>    <span class="p">[]()</span> <span class="o">-></span> <span class="kt">int</span> <span class="p">{</span><span class="k">return</span> <span class="mi">0</span><span class="p">;}</span> <span class="c1">// result factory);</span>
<span class="c1"></span>
<span class="p">{</span>
  <span class="c1">// As a task passed to an executor</span>
<span class="c1"></span>  <span class="n">TrivialFuture</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">></span> <span class="n">inputFuture</span><span class="p">{</span><span class="mi">2</span><span class="p">};</span>
  <span class="k">auto</span> <span class="n">executorResultF</span> <span class="o">=</span>
    <span class="n">BulkExecutor</span><span class="p">{}.</span><span class="n">then_execute</span><span class="p">(</span><span class="n">continuation</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputFuture</span><span class="p">));</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">future_get</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">executorResultF</span><span class="p">))</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">{</span>
  <span class="c1">// As a task passed to a future</span>
<span class="c1"></span>  <span class="n">TrivialFuture</span><span class="o">&lt;</span><span class="kt">int</span><span class="o">></span> <span class="n">inputFuture</span><span class="p">{</span><span class="mi">2</span><span class="p">};</span>
  <span class="k">auto</span> <span class="n">futureResultF</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputFuture</span><span class="p">).</span><span class="n">then</span><span class="p">(</span><span class="n">continuation</span><span class="p">);</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">this_thread</span><span class="o">::</span><span class="n">future_get</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">futureResultF</span><span class="p">))</span> <span class="o">&lt;&lt;</span> <span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">;</span>
<span class="p">}</span>
</pre>
   <p>The mechanism here is an extension of the non-bulk continuation type. Where for
non-bulk tasks the continuation was:</p>
   <blockquote>
    <p>An object that, when passed a Promise as a parameter
constructs a new object that is itself a Promise.</p>
   </blockquote>
   <p>Bulk is similar, but a little more complicated to allow an arbitrary executor to hook up the bulk algorithm.</p>
   <blockquote>
    <p>An object that, when passed a Promise as a parameter
constructs a new object that, when passed a BulkDriver as a parameter,
returns a promise.</p>
   </blockquote>
   <p>That is that we add a stage to the setup algorithm that allows the executor to configure the execution.</p>
   <p><code class="highlight"><span class="n">bulk_on_value</span></code> becomes a function that returns a nested type:</p>
<pre class="highlight"><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">F</span><span class="p">,</span> <span class="k">class</span> <span class="nc">Shape</span><span class="p">,</span> <span class="k">class</span> <span class="nc">RF</span><span class="o">></span>
<span class="k">auto</span> <span class="n">bulk_on_value</span><span class="p">(</span>
    <span class="n">F</span><span class="o">&amp;&amp;</span> <span class="n">continuationFunction</span><span class="p">,</span>
    <span class="n">Shape</span> <span class="n">s</span><span class="p">,</span>
    <span class="n">RF</span><span class="o">&amp;&amp;</span> <span class="n">resultFactory</span><span class="p">)</span> <span class="p">{</span>
  <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
          <span class="n">resultFactory</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">RF</span><span class="o">></span><span class="p">(</span><span class="n">resultFactory</span><span class="p">),</span>
          <span class="n">s</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">></span><span class="p">(</span><span class="n">s</span><span class="p">)](</span>
        <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
    <span class="k">using</span> <span class="n">OutputPromiseRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">outputPromise</span><span class="p">);</span>
    <span class="k">using</span> <span class="n">OutputPromise</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

    <span class="k">return</span> <span class="p">[</span><span class="n">continuationFunction</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
            <span class="n">resultFactory</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">RF</span><span class="o">></span><span class="p">(</span><span class="n">resultFactory</span><span class="p">),</span>
            <span class="n">s</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">Shape</span><span class="o">></span><span class="p">(</span><span class="n">s</span><span class="p">),</span>
            <span class="n">outputPromise</span> <span class="o">=</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">)](</span>
          <span class="k">auto</span><span class="o">&amp;&amp;</span> <span class="n">bulkDriver</span><span class="p">)</span> <span class="k">mutable</span> <span class="p">{</span>
      <span class="k">using</span> <span class="n">BulkDriverRef</span> <span class="o">=</span> <span class="k">decltype</span><span class="p">(</span><span class="n">bulkDriver</span><span class="p">);</span>
      <span class="k">using</span> <span class="n">BulkDriver</span> <span class="o">=</span> <span class="k">typename</span> <span class="n">std</span><span class="o">::</span><span class="n">remove_reference</span><span class="o">&lt;</span><span class="n">BulkDriverRef</span><span class="o">>::</span><span class="n">type</span><span class="p">;</span>

      <span class="k">return</span> <span class="n">InputPromise</span><span class="o">&lt;</span><span class="n">F</span><span class="p">,</span> <span class="n">OutputPromise</span><span class="p">,</span> <span class="n">Shape</span><span class="p">,</span> <span class="n">RF</span><span class="p">,</span> <span class="n">BulkDriver</span><span class="o">></span><span class="p">(</span>
          <span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">continuationFunction</span><span class="p">),</span>
          <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OutputPromiseRef</span><span class="o">></span><span class="p">(</span><span class="n">outputPromise</span><span class="p">),</span>
          <span class="n">resultFactory</span><span class="p">(),</span>
          <span class="n">s</span><span class="p">,</span>
          <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">bulkDriver</span><span class="p">)</span><span class="o">></span><span class="p">(</span><span class="n">bulkDriver</span><span class="p">));</span>
    <span class="p">};</span>
  <span class="p">};</span>
<span class="p">}</span>
</pre>
   <p>all this does is pass through the data, but defer binding of the output promise type and bulk driver type, effectively to construction of a later object.
This approach ensures the greatest level of type visibility to the compiler and the most efficient, allocation-free code.</p>
   <p>The bulk driver exposes an interface that a given task constructor can hook in to, but is under control of the executor such that the implementation of the operations is under the control of the target.
For example, a very simple driver that runs the entire algorithm when the executor calls the <code class="highlight"><span class="n">end</span><span class="p">()</span></code> method on the driver might look like:</p>
<pre class="highlight"><span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">PromiseT</span><span class="p">,</span> <span class="k">class</span> <span class="nc">ShapeF</span><span class="p">,</span> <span class="k">class</span> <span class="nc">AtF</span><span class="p">,</span> <span class="k">class</span> <span class="nc">DoneF</span><span class="o">></span>
<span class="k">struct</span> <span class="n">EndDriverImpl</span> <span class="p">{</span>
  <span class="kt">void</span> <span class="n">start</span><span class="p">()</span> <span class="p">{</span>
  <span class="p">}</span>

  <span class="kt">void</span> <span class="n">end</span><span class="p">()</span> <span class="p">{</span>
    <span class="k">const</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">shape</span> <span class="o">=</span> <span class="n">shapeF_</span><span class="p">();</span>
    <span class="k">for</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">decay_t</span><span class="o">&lt;</span><span class="k">decltype</span><span class="p">(</span><span class="n">shape</span><span class="p">)</span><span class="o">></span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">shape</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span><span class="p">)</span> <span class="p">{</span>
      <span class="n">atF_</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
    <span class="p">}</span>
    <span class="n">doneF_</span><span class="p">();</span>
  <span class="p">}</span>

  <span class="n">PromiseT</span><span class="o">&amp;</span> <span class="n">promise_</span><span class="p">;</span>
  <span class="n">ShapeF</span> <span class="n">shapeF_</span><span class="p">;</span>
  <span class="n">AtF</span> <span class="n">atF_</span><span class="p">;</span>
  <span class="n">DoneF</span> <span class="n">doneF_</span><span class="p">;</span>
<span class="p">};</span>

<span class="k">struct</span> <span class="n">EndDriver</span> <span class="p">{</span>
  <span class="k">template</span><span class="o">&lt;</span><span class="k">class</span> <span class="nc">PromiseT</span><span class="p">,</span> <span class="k">class</span> <span class="nc">ShapeF</span><span class="p">,</span> <span class="k">class</span> <span class="nc">AtF</span><span class="p">,</span> <span class="k">class</span> <span class="nc">DoneF</span><span class="o">></span>
  <span class="k">auto</span> <span class="k">operator</span><span class="p">()(</span><span class="n">PromiseT</span><span class="o">&amp;</span> <span class="n">prom</span><span class="p">,</span> <span class="n">ShapeF</span><span class="o">&amp;&amp;</span> <span class="n">shapeF</span><span class="p">,</span> <span class="n">AtF</span><span class="o">&amp;&amp;</span> <span class="n">atF</span><span class="p">,</span> <span class="n">DoneF</span><span class="o">&amp;&amp;</span> <span class="n">doneF</span><span class="p">){</span>
    <span class="k">return</span> <span class="n">EndDriverImpl</span><span class="o">&lt;</span><span class="n">PromiseT</span><span class="p">,</span> <span class="n">ShapeF</span><span class="p">,</span> <span class="n">AtF</span><span class="p">,</span> <span class="n">DoneF</span><span class="o">></span><span class="p">{</span>
      <span class="n">prom</span><span class="p">,</span>
      <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">ShapeF</span><span class="o">></span><span class="p">(</span><span class="n">shapeF</span><span class="p">),</span>
      <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">AtF</span><span class="o">></span><span class="p">(</span><span class="n">atF</span><span class="p">),</span>
      <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">DoneF</span><span class="o">></span><span class="p">(</span><span class="n">doneF</span><span class="p">)};</span>
  <span class="p">}</span>
<span class="p">};</span>
</pre>
   <p>We add to the promise interface a <code class="highlight"><span class="n">get_driver</span><span class="p">()</span></code> method that will return the driver:</p>
<pre class="highlight"><span class="k">auto</span> <span class="nf">bulk_driver</span><span class="p">()</span> <span class="p">{</span>
  <span class="k">return</span> <span class="n">bulkDriver_</span><span class="p">(</span>
    <span class="o">*</span><span class="k">this</span><span class="p">,</span>
    <span class="p">[</span><span class="k">this</span><span class="p">](){</span><span class="k">return</span> <span class="k">this</span><span class="o">-></span><span class="n">get_shape</span><span class="p">();},</span>
    <span class="p">[</span><span class="k">this</span><span class="p">](</span><span class="k">auto</span> <span class="n">i</span><span class="p">){</span><span class="k">this</span><span class="o">-></span><span class="n">execute_at</span><span class="p">(</span><span class="n">i</span><span class="p">);},</span>
    <span class="p">[</span><span class="k">this</span><span class="p">](){</span><span class="k">this</span><span class="o">-></span><span class="n">done</span><span class="p">();});</span>
<span class="p">}</span>
</pre>
   <p>Remember, the Promise was constructed by the task - so the means of constructing the driver is under task control, but the driver type is under Executor control.
The executor then is free to setup and run the algorithm as it sees fit, calling the functions passed to the driver’s constructor through whatever means necessary.
For example, when the input future is satisfied and the executor knows the value is ready, it might call:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">driver</span> <span class="o">=</span> <span class="n">boundCont</span><span class="p">.</span><span class="n">bulk_driver</span><span class="p">();</span>
<span class="n">boundCont</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">inputFuture</span><span class="p">).</span><span class="n">get</span><span class="p">());</span>
<span class="n">driver</span><span class="p">.</span><span class="n">start</span><span class="p">();</span>
<span class="n">driver</span><span class="p">.</span><span class="n">end</span><span class="p">();</span>
</pre>
   <p>such that the call to end() runs the above sequence of calls into the task.
That <code class="highlight"><span class="n">end</span><span class="p">()</span></code> method could of course be implemented as an openmp parallel loop, a CUDA dispatch or any similar operation.</p>
   <p>The BulkDriver is defined as being a function that takes:</p>
   <ul>
    <li data-md="">
     <p>A reference to the input promise (a reference to the current continuation).</p>
    <li data-md="">
     <p>A nullary function that when called, returns the shape.</p>
    <li data-md="">
     <p>A function that executes the continuation at some point in the shape, and takes an element from the shape range.</p>
    <li data-md="">
     <p>A function to call on completion of the bulk execution.</p>
   </ul>
   <h3 class="heading settled" data-level="7.2" id="an-opportunity-rethinking-the-bulk-parameterisation"><span class="secno">7.2. </span><span class="content">An opportunity: rethinking the bulk parameterisation</span><a class="self-link" href="#an-opportunity-rethinking-the-bulk-parameterisation"></a></h3>
    Abstracting the execution algorithm offers us the opportunity to be flexible about the design of the continuation. 
   <p>As one example, when we were considering the design of bulk, we realised that there are some limitations:</p>
   <ul>
    <li data-md="">
     <p>The shape is defined only at graph construction time.</p>
    <li data-md="">
     <p>Shared state and output can not be constructed dependent on the input.</p>
    <li data-md="">
     <p>The output has to map directly to the output future. This makes it hard to, for example, perform a final accumulation into an atomic because atomics are not movable.</p>
   </ul>
   <p>We therefore propose extending the definition of the continuation:</p>
   <ul>
    <li data-md="">
     <p>Instead of a static shape we have a shape factory, that also takes the input by reference.
   Note that this can be constexpr and ignore its input to regain the original behaviour.</p>
    <li data-md="">
     <p>The shared state factory be extended to take the shape and input value.</p>
    <li data-md="">
     <p>The output factory be replaced by an output selector, parameterised by the shared state and output promise, such that the output is transferred from the shared state to the output promise.</p>
   </ul>
   <p>Most importantly, this proposal is merely for the bulk_on_value continuation construction function we might consider putting into the standard library.
It does not require a change to the BulkDriver design - the design is multi stage which allows the continuation to interact however it needs to.</p>
   <p>Instead we might modify <code class="highlight"><span class="n">bulk_on_value</span></code> to be constructed as follows:</p>
<pre class="highlight"><span class="k">auto</span> <span class="n">continuation</span> <span class="o">=</span> <span class="n">bulk_on_value</span><span class="p">(</span>
    <span class="p">[](</span><span class="k">const</span> <span class="n">InputT</span><span class="o">&amp;</span> <span class="n">input</span><span class="p">,</span> <span class="n">ShapeElementT</span> <span class="cm">/*idx*/</span><span class="p">,</span> <span class="n">SharedStateT</span> <span class="o">&amp;</span><span class="n">shared</span><span class="p">){</span><span class="o">*</span><span class="n">shared</span><span class="o">+=</span><span class="n">input</span><span class="p">;},</span> <span class="c1">// Operation</span>
<span class="c1"></span>    <span class="p">[](</span><span class="k">const</span> <span class="n">InputT</span><span class="o">&amp;</span> <span class="cm">/*input value*/</span><span class="p">){</span><span class="k">return</span> <span class="kt">int</span><span class="p">{</span><span class="mi">20</span><span class="p">};},</span> <span class="c1">// Shape factory.</span>
<span class="c1"></span>    <span class="p">[](</span><span class="k">const</span> <span class="n">ShapeT</span><span class="o">&amp;</span> <span class="cm">/*shape*/</span><span class="p">,</span> <span class="k">const</span> <span class="n">InputT</span><span class="o">&amp;</span> <span class="cm">/*input value*/</span><span class="p">)</span> <span class="o">-></span> <span class="n">SharedStateT</span> <span class="p">{</span><span class="k">return</span> <span class="p">{</span><span class="mi">0</span><span class="p">};},</span> <span class="c1">// Shared factory</span>
<span class="c1"></span>    <span class="p">[](</span><span class="n">SharedStateT</span><span class="o">&amp;&amp;</span> <span class="n">shared</span><span class="p">,</span> <span class="k">auto</span><span class="o">&amp;</span> <span class="n">outputPromise</span><span class="p">)</span> <span class="p">{</span>  <span class="c1">// Result selector/output</span>
<span class="c1"></span>      <span class="n">outputPromise</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="o">*</span><span class="n">shared</span><span class="p">));</span>
    <span class="p">});</span>
</pre>
   <p>This only changes the implementation of the task - the basic algorithm the <code class="highlight"><span class="n">BulkDriver</span></code> executes need not change if we define it correctly.</p>
   <h2 class="heading settled" data-level="8" id="wording"><span class="secno">8. </span><span class="content">Proposed New Wording for P0443</span><a class="self-link" href="#wording"></a></h2>
   <h3 class="heading settled" data-level="8.1" id="promiserequire"><span class="secno">8.1. </span><span class="content"><code class="highlight"><span class="n">Promise</span></code> requirements</span><a class="self-link" href="#promiserequire"></a></h3>
   <p>A type <code class="highlight"><span class="n">P</span></code> meets the <code class="highlight"><span class="n">Promise</span></code> requirements for some value type <code class="highlight"><span class="n">T</span></code> if an
instance <code class="highlight"><span class="n">p</span></code> of <code class="highlight"><span class="n">P</span></code> satisfies the requirements in the table below.</p>
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">T</span><span class="o">&amp;&amp;</span><span class="p">)</span></code>
      <td>void
      <td> Defined if T is not void. Completes the promise with a value.
      Should accept by forwarding reference. 
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>
      <td>void
      <td>Defined if T is void. Completes the promise with no value.
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span><span class="p">)</span></code>
      <td>void
      <td> Completes the promise with an exception wrapped in a <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code>. 
   </table>
   <h3 class="heading settled" data-level="8.2" id="onewayrequire"><span class="secno">8.2. </span><span class="content">OneWayFutureContinuation requirements</span><a class="self-link" href="#onewayrequire"></a></h3>
    A type <code class="highlight"><span class="n">OFC</span></code> meets the OneWayFutureContinuation requirements if <code class="highlight"><span class="n">OFC</span></code> satisfies
the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code> and for an instance <code class="highlight"><span class="n">ofc</span></code> of <code class="highlight"><span class="n">OFC</span></code>, <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">OFC</span><span class="o">></span><span class="p">(</span><span class="n">ofc</span><span class="p">))</span></code> is valid. 
   <h3 class="heading settled" data-level="8.3" id="twowayrequire"><span class="secno">8.3. </span><span class="content">TwoWayFutureContinuation requirements</span><a class="self-link" href="#twowayrequire"></a></h3>
    A type <code class="highlight"><span class="n">TFC</span></code> meets the <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> requirements if <code class="highlight"><span class="n">TFC</span></code> satisfies the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code> and for an instance <code class="highlight"><span class="n">tfc</span></code> of <code class="highlight"><span class="n">TFC</span></code> and  a value <code class="highlight"><span class="n">p</span></code> whose type, <code class="highlight"><span class="n">P</span></code> satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements and
for which <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code> is valid. 
   <h3 class="heading settled" data-level="8.4" id="thenrequire"><span class="secno">8.4. </span><span class="content">ThenFutureContinuation requirements</span><a class="self-link" href="#thenrequire"></a></h3>
    A type <code class="highlight"><span class="n">THFC</span></code> meets the <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> requirements if <code class="highlight"><span class="n">THFC</span></code> satisfies the requirements of <code class="highlight"><span class="n">MoveConstructible</span></code>, and for an
instance <code class="highlight"><span class="n">thfc</span></code> of <code class="highlight"><span class="n">TFC</span></code> and a value <code class="highlight"><span class="n">p</span></code> whose type, <code class="highlight"><span class="n">P</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements and where <code class="highlight"><span class="n">INVOKE</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">P</span><span class="o">></span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code> is valid and
returns a value <code class="highlight"><span class="n">pout</span></code> of type <code class="highlight"><span class="n">POUT</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements
for some value type <code class="highlight"><span class="n">TIn</span></code>, potentially <code class="highlight"><span class="kt">void</span></code>, that is known to the caller. 
   <h3 class="heading settled" data-level="8.5" id="onewaychanges"><span class="secno">8.5. </span><span class="content">Changes to OneWayExecutor requirements</span><a class="self-link" href="#onewaychanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code> and <code class="highlight"><span class="n">f</span></code> denotes an object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements
of <code class="highlight"><span class="n">OneWayFutureContinuation</span></code>. 
   <h3 class="heading settled" data-level="8.6" id="twowaychanges"><span class="secno">8.6. </span><span class="content">Changes to TwoWayExecutor requirements</span><a class="self-link" href="#twowaychanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code>, <code class="highlight"><span class="n">f</span></code> denotes a an object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements of <code class="highlight"><span class="n">TwoWayFutureContinuation</span></code> and <code class="highlight"><span class="n">R</span></code> is <code class="highlight"><span class="kt">void</span></code> or denotes the value type of a
value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span><span class="o">&amp;&amp;</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code> and that may be passed to the expression <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code>. 
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">twoway_execute</span><span class="p">(</span><span class="n">f</span><span class="p">)</span></code>
      <td> A type that satisfies the Future requirements for the value type <code class="highlight"><span class="n">R</span></code>. 
      <td>
        Creates an execution agent which invokes <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code> for some value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span></code> that
      satisfies the requirements of <code class="highlight"><span class="n">Promise</span></code> for value type <code class="highlight"><span class="n">R</span></code>, with the call
      to <code class="highlight"><span class="n">DECAY_COPY</span></code> being evaluated in the thread that called <code class="highlight"><span class="n">twoway_execute</span></code>. 
       <p>
        May block pending completion of DECAY_COPY( std::forward
        <f>(f))(p).</f>
       </p>
       <p>The invocation of twoway_execute synchronizes with
      (C++Std [intro.multithread]) the invocation of f.</p>
       <p>Stores the result of a call to <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>, or <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code> for <code class="highlight"><span class="n">r</span></code> of type <code class="highlight"><span class="n">R</span></code> or <code class="highlight"><span class="n">e</span></code> of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> in the associated shared state of the resulting <code class="highlight"><span class="n">Future</span></code>.</p>
   </table>
   <h3 class="heading settled" data-level="8.7" id="thenchanges"><span class="secno">8.7. </span><span class="content">Changes to ThenExecutor requirements</span><a class="self-link" href="#thenchanges"></a></h3>
    In the Table below, <code class="highlight"><span class="n">x</span></code> denotes a (possibly const) executor object of type <code class="highlight"><span class="n">X</span></code>, <code class="highlight"><span class="n">fut</span></code> denotes a future object satisfying the <code class="highlight"><span class="n">Future</span></code> requirements, <code class="highlight"><span class="n">f</span></code> denotes
a function object of type <code class="highlight"><span class="n">F</span><span class="o">&amp;&amp;</span></code> that satisfies the requirements of <code class="highlight"><span class="n">ThenFutureContinuation</span></code> and <code class="highlight"><span class="n">R</span></code> is <code class="highlight"><span class="kt">void</span></code> or denotes the value type of a value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span><span class="o">&amp;&amp;</span></code> that satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code> and that may be passed to the expression <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">std</span><span class="o">::</span><span class="n">move</span><span class="p">(</span><span class="n">p</span><span class="p">))</span></code>. 
   <table>
    <tbody>
     <tr>
      <th>Expression
      <th>Return Type
      <th>Operational semantics
     <tr>
      <td><code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">then_execute</span><span class="p">(</span><span class="n">f</span><span class="p">,</span> <span class="n">fut</span><span class="p">)</span></code>
      <td> A type that satisfies the Future requirements for the value type <code class="highlight"><span class="n">R</span></code>. 
      <td>
        When <code class="highlight"><span class="n">fut</span></code> is ready, creates an execution agent which invokes <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code> for some value <code class="highlight"><span class="n">p</span></code> of type <code class="highlight"><span class="n">P</span></code> that
      satisfies the <code class="highlight"><span class="n">Promise</span></code> requirements for value type <code class="highlight"><span class="n">R</span></code>, with the call to <code class="highlight"><span class="n">DECAY_COPY</span></code> being evaluated in the thread that called then_execute. 
       <p>May block pending completion of <code class="highlight"><span class="n">DECAY_COPY</span><span class="p">(</span> <span class="n">std</span><span class="o">::</span><span class="n">forward</span><span class="o">&lt;</span><span class="n">F</span><span class="o">></span><span class="p">(</span><span class="n">f</span><span class="p">))(</span><span class="n">p</span><span class="p">)</span></code>.</p>
       <p>The invocation of <code class="highlight"><span class="n">then_execute</span></code> synchronizes with (C++Std
      [intro.multithread]) the invocation of <code class="highlight"><span class="n">f</span></code>.</p>
       <p>If <code class="highlight"><span class="n">fut</span></code> is ready with a value, calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, if <code class="highlight"><span class="n">fut</span></code> is ready
      and the value is void calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>. If <code class="highlight"><span class="n">fut</span></code> is ready with an
      exception calls <code class="highlight"><span class="n">f</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code>.</p>
       <p>Stores the result of a call to <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">(</span><span class="n">r</span><span class="p">)</span></code>, <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_value</span><span class="p">()</span></code>, or <code class="highlight"><span class="n">p</span><span class="p">.</span><span class="n">set_exception</span><span class="p">(</span><span class="n">e</span><span class="p">)</span></code> for <code class="highlight"><span class="n">r</span></code> of type <code class="highlight"><span class="n">R</span></code> or <code class="highlight"><span class="n">e</span></code> of type <code class="highlight"><span class="n">std</span><span class="o">::</span><span class="n">exception_ptr</span></code> in the associated shared state of the resulting <code class="highlight"><span class="n">Future</span></code>.</p>
   </table>
   <h3 class="heading settled" data-level="8.8" id="bulkchanges"><span class="secno">8.8. </span><span class="content">Changes to Bulk requirements in general</span><a class="self-link" href="#bulkchanges"></a></h3>
    Precise wording TBD. Roughly: 
   <ul>
    <li data-md="">
     <p>Remove bulk APIs from executor concepts.</p>
    <li data-md="">
     <p>Define bulk continuation concepts as generalisations of the non-bulk continuation concepts.</p>
    <li data-md="">
     <p>Define bulk driver concept.</p>
   </ul>
   <p>This will cleanly extend to adding a wider set of abstractions beyond basic bulk, orthogonally to the basic executor interface.</p>
  </main>
<script>
(function() {
  "use strict";
  var collapseSidebarText = '<span aria-hidden="true">←</span> '
                          + '<span>Collapse Sidebar</span>';
  var expandSidebarText   = '<span aria-hidden="true">→</span> '
                          + '<span>Pop Out Sidebar</span>';
  var tocJumpText         = '<span aria-hidden="true">↑</span> '
                          + '<span>Jump to Table of Contents</span>';

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

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

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

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

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

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


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

    tocNav.appendChild(toggle);
  }

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

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

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

})();
</script>