<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="mpark/wg21" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <meta name="dcterms.date" content="2025-06-18" />
  <title>Reconsider parallel `ranges::rotate_copy` and
`ranges::reverse_copy`</title>
  <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
      div.csl-block{margin-left: 1.5em;}
      ul.task-list{list-style: none;}
      pre > code.sourceCode { white-space: pre; position: relative; }
      pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
      pre > code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      pre > code.sourceCode { white-space: pre-wrap; }
      pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          color: #aaaaaa;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
      div.sourceCode
        {  background-color: #f6f8fa; }
      @media screen {
      pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span { } /* Normal */
      code span.al { color: #ff0000; } /* Alert */
      code span.an { } /* Annotation */
      code span.at { } /* Attribute */
      code span.bn { color: #9f6807; } /* BaseN */
      code span.bu { color: #9f6807; } /* BuiltIn */
      code span.cf { color: #00607c; } /* ControlFlow */
      code span.ch { color: #9f6807; } /* Char */
      code span.cn { } /* Constant */
      code span.co { color: #008000; font-style: italic; } /* Comment */
      code span.cv { color: #008000; font-style: italic; } /* CommentVar */
      code span.do { color: #008000; } /* Documentation */
      code span.dt { color: #00607c; } /* DataType */
      code span.dv { color: #9f6807; } /* DecVal */
      code span.er { color: #ff0000; font-weight: bold; } /* Error */
      code span.ex { } /* Extension */
      code span.fl { color: #9f6807; } /* Float */
      code span.fu { } /* Function */
      code span.im { } /* Import */
      code span.in { color: #008000; } /* Information */
      code span.kw { color: #00607c; } /* Keyword */
      code span.op { color: #af1915; } /* Operator */
      code span.ot { } /* Other */
      code span.pp { color: #6f4e37; } /* Preprocessor */
      code span.re { } /* RegionMarker */
      code span.sc { color: #9f6807; } /* SpecialChar */
      code span.ss { color: #9f6807; } /* SpecialString */
      code span.st { color: #9f6807; } /* String */
      code span.va { } /* Variable */
      code span.vs { color: #9f6807; } /* VerbatimString */
      code span.wa { color: #008000; font-weight: bold; } /* Warning */
      code.diff {color: #898887}
      code.diff span.va {color: #006e28}
      code.diff span.st {color: #bf0303}
  </style>
  <style type="text/css">
body {
margin: 5em;
font-family: serif;

hyphens: auto;
line-height: 1.35;
text-align: justify;
}
@media screen and (max-width: 30em) {
body {
margin: 1.5em;
}
}
div.wrapper {
max-width: 60em;
margin: auto;
}
ul {
list-style-type: none;
padding-left: 2em;
margin-top: -0.2em;
margin-bottom: -0.2em;
}
a {
text-decoration: none;
color: #4183C4;
}
a.hidden_link {
text-decoration: none;
color: inherit;
}
li {
margin-top: 0.6em;
margin-bottom: 0.6em;
}
h1, h2, h3, h4 {
position: relative;
line-height: 1;
}
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;
font-family: sans-serif;
font-weight: normal;
font-size: 83%;
}
a.self-link:hover { opacity: 1; }
a.self-link::before { content: "§"; }
ul > li:before {
content: "\2014";
position: absolute;
margin-left: -1.5em;
}
:target { background-color: #C9FBC9; }
:target .codeblock { background-color: #C9FBC9; }
:target ul { background-color: #C9FBC9; }
.abbr_ref { float: right; }
.folded_abbr_ref { float: right; }
:target .folded_abbr_ref { display: none; }
:target .unfolded_abbr_ref { float: right; display: inherit; }
.unfolded_abbr_ref { display: none; }
.secnum { display: inline-block; min-width: 35pt; }
.header-section-number { display: inline-block; min-width: 35pt; }
.annexnum { display: block; }
div.sourceLinkParent {
float: right;
}
a.sourceLink {
position: absolute;
opacity: 0;
margin-left: 10pt;
}
a.sourceLink:hover {
opacity: 1;
}
a.itemDeclLink {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
opacity: 0;
}
a.itemDeclLink:hover { opacity: 1; }
span.marginalizedparent {
position: relative;
left: -5em;
}
li span.marginalizedparent { left: -7em; }
li ul > li span.marginalizedparent { left: -9em; }
li ul > li ul > li span.marginalizedparent { left: -11em; }
li ul > li ul > li ul > li span.marginalizedparent { left: -13em; }
div.footnoteNumberParent {
position: relative;
left: -4.7em;
}
a.marginalized {
position: absolute;
font-size: 75%;
text-align: right;
width: 5em;
}
a.enumerated_item_num {
position: relative;
left: -3.5em;
display: inline-block;
margin-right: -3em;
text-align: right;
width: 3em;
}
div.para { margin-bottom: 0.6em; margin-top: 0.6em; text-align: justify; }
div.section { text-align: justify; }
div.sentence { display: inline; }
span.indexparent {
display: inline;
position: relative;
float: right;
right: -1em;
}
a.index {
position: absolute;
display: none;
}
a.index:before { content: "⟵"; }

a.index:target {
display: inline;
}
.indexitems {
margin-left: 2em;
text-indent: -2em;
}
div.itemdescr {
margin-left: 3em;
}
.bnf {
font-family: serif;
margin-left: 40pt;
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ncbnf {
font-family: serif;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
}
.ncsimplebnf {
font-family: serif;
font-style: italic;
margin-top: 0.5em;
margin-bottom: 0.5em;
margin-left: 40pt;
background: inherit; 
}
span.textnormal {
font-style: normal;
font-family: serif;
white-space: normal;
display: inline-block;
}
span.rlap {
display: inline-block;
width: 0px;
}
span.descr { font-style: normal; font-family: serif; }
span.grammarterm { font-style: italic; }
span.term { font-style: italic; }
span.terminal { font-family: monospace; font-style: normal; }
span.nonterminal { font-style: italic; }
span.tcode { font-family: monospace; font-style: normal; }
span.textbf { font-weight: bold; }
span.textsc { font-variant: small-caps; }
a.nontermdef { font-style: italic; font-family: serif; }
span.emph { font-style: italic; }
span.techterm { font-style: italic; }
span.mathit { font-style: italic; }
span.mathsf { font-family: sans-serif; }
span.mathrm { font-family: serif; font-style: normal; }
span.textrm { font-family: serif; }
span.textsl { font-style: italic; }
span.mathtt { font-family: monospace; font-style: normal; }
span.mbox { font-family: serif; font-style: normal; }
span.ungap { display: inline-block; width: 2pt; }
span.textit { font-style: italic; }
span.texttt { font-family: monospace; }
span.tcode_in_codeblock { font-family: monospace; font-style: normal; }
span.phantom { color: white; }

span.math { font-style: normal; }
span.mathblock {
display: block;
margin-left: auto;
margin-right: auto;
margin-top: 1.2em;
margin-bottom: 1.2em;
text-align: center;
}
span.mathalpha {
font-style: italic;
}
span.synopsis {
font-weight: bold;
margin-top: 0.5em;
display: block;
}
span.definition {
font-weight: bold;
display: block;
}
.codeblock {
margin-left: 1.2em;
line-height: 127%;
}
.outputblock {
margin-left: 1.2em;
line-height: 127%;
}
div.itemdecl {
margin-top: 2ex;
}
code.itemdeclcode {
white-space: pre;
display: block;
}
span.textsuperscript {
vertical-align: super;
font-size: smaller;
line-height: 0;
}
.footnotenum { vertical-align: super; font-size: smaller; line-height: 0; }
.footnote {
font-size: small;
margin-left: 2em;
margin-right: 2em;
margin-top: 0.6em;
margin-bottom: 0.6em;
}
div.minipage {
display: inline-block;
margin-right: 3em;
}
div.numberedTable {
text-align: center;
margin: 2em;
}
div.figure {
text-align: center;
margin: 2em;
}
table {
border: 1px solid black;
border-collapse: collapse;
margin-left: auto;
margin-right: auto;
margin-top: 0.8em;
text-align: left;
hyphens: none; 
}
td, th {
padding-left: 1em;
padding-right: 1em;
vertical-align: top;
}
td.empty {
padding: 0px;
padding-left: 1px;
}
td.left {
text-align: left;
}
td.right {
text-align: right;
}
td.center {
text-align: center;
}
td.justify {
text-align: justify;
}
td.border {
border-left: 1px solid black;
}
tr.rowsep, td.cline {
border-top: 1px solid black;
}
tr.even, tr.odd {
border-bottom: 1px solid black;
}
tr.capsep {
border-top: 3px solid black;
border-top-style: double;
}
tr.header {
border-bottom: 3px solid black;
border-bottom-style: double;
}
th {
border-bottom: 1px solid black;
}
span.centry {
font-weight: bold;
}
div.table {
display: block;
margin-left: auto;
margin-right: auto;
text-align: center;
width: 90%;
}
span.indented {
display: block;
margin-left: 2em;
margin-bottom: 1em;
margin-top: 1em;
}
ol.enumeratea { list-style-type: none; background: inherit; }
ol.enumerate { list-style-type: none; background: inherit; }

code.sourceCode > span { display: inline; }
</style>
  <link href="data:image/x-icon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAVoJEAN6CRADegkQAWIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wCCRAAAgkQAAIJEAACCRAAsgkQAvoJEAP+CRAD/gkQA/4JEAP+CRADAgkQALoJEAACCRAAAgkQAAP///wD///8AgkQAAIJEABSCRACSgkQA/IJEAP99PQD/dzMA/3czAP99PQD/gkQA/4JEAPyCRACUgkQAFIJEAAD///8A////AHw+AFiBQwDqgkQA/4BBAP9/PxP/uZd6/9rJtf/bybX/upd7/39AFP+AQQD/gkQA/4FDAOqAQgBc////AP///wDKklv4jlEa/3o7AP+PWC//8+3o///////////////////////z7un/kFox/35AAP+GRwD/mVYA+v///wD///8A0Zpk+NmibP+0d0T/8evj///////+/fv/1sKz/9bCs//9/fr//////+/m2/+NRwL/nloA/5xYAPj///8A////ANKaZPjRmGH/5cKh////////////k149/3UwAP91MQD/lmQ//86rhv+USg3/m1YA/5hSAP+bVgD4////AP///wDSmmT4zpJY/+/bx///////8+TV/8mLT/+TVx//gkIA/5lVAP+VTAD/x6B//7aEVv/JpH7/s39J+P///wD///8A0ppk+M6SWP/u2sf///////Pj1f/Nj1T/2KFs/8mOUv+eWhD/lEsA/8aee/+0glT/x6F7/7J8Rvj///8A////ANKaZPjRmGH/48Cf///////+/v7/2qt//82PVP/OkFX/37KJ/86siv+USg7/mVQA/5hRAP+bVgD4////AP///wDSmmT40ppk/9CVXP/69O////////7+/v/x4M//8d/P//7+/f//////9u7n/6tnJf+XUgD/nFgA+P///wD///8A0ppk+NKaZP/RmWL/1qNy//r07///////////////////////+vXw/9akdP/Wnmn/y5FY/6JfFvj///8A////ANKaZFTSmmTo0ppk/9GYYv/Ql1//5cWm//Hg0P/x4ND/5cWm/9GXYP/RmGH/0ppk/9KaZOjVnmpY////AP///wDSmmQA0ppkEtKaZI7SmmT60ppk/9CWX//OkVb/zpFW/9CWX//SmmT/0ppk/NKaZJDSmmQS0ppkAP///wD///8A0ppkANKaZADSmmQA0ppkKtKaZLrSmmT/0ppk/9KaZP/SmmT/0ppkvNKaZCrSmmQA0ppkANKaZAD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkUtKaZNzSmmTc0ppkVNKaZADSmmQA0ppkANKaZADSmmQA////AP5/AAD4HwAA4AcAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADgBwAA+B8AAP5/AAAoAAAAIAAAAEAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAyCRACMgkQA6oJEAOqCRACQgkQAEIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRABigkQA5oJEAP+CRAD/gkQA/4JEAP+CRADqgkQAZoJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAA4gkQAwoJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQAxIJEADyCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAAgkQAAP///wD///8A////AP///wCCRAAAgkQAAIJEAACCRAAAgkQAAIJEAACCRAAWgkQAmIJEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAJyCRAAYgkQAAIJEAACCRAAAgkQAAIJEAACCRAAA////AP///wD///8A////AIJEAACCRAAAgkQAAIJEAACCRAAAgkQAdIJEAPCCRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAP+CRAD/gkQA/4JEAPSCRAB4gkQAAIJEAACCRAAAgkQAAIJEAAD///8A////AP///wD///8AgkQAAIJEAACCRAAAgkQASoJEANKCRAD/gkQA/4JEAP+CRAD/g0YA/39AAP9zLgD/bSQA/2shAP9rIQD/bSQA/3MuAP9/PwD/g0YA/4JEAP+CRAD/gkQA/4JEAP+CRADUgkQAToJEAACCRAAAgkQAAP///wD///8A////AP///wB+PwAAgkUAIoJEAKiCRAD/gkQA/4JEAP+CRAD/hEcA/4BBAP9sIwD/dTAA/5RfKv+viF7/vp56/76ee/+wiF7/lWAr/3YxAP9sIwD/f0AA/4RHAP+CRAD/gkQA/4JEAP+CRAD/gkQArIJEACaBQwAA////AP///wD///8A////AIBCAEBzNAD6f0EA/4NFAP+CRAD/gkQA/4VIAP92MwD/bSUA/6N1Tv/ezsL/////////////////////////////////38/D/6V3Uv9uJgD/dTEA/4VJAP+CRAD/gkQA/4JEAP+BQwD/fUAA/4FDAEj///8A////AP///wD///8AzJRd5qBlKf91NgD/dDUA/4JEAP+FSQD/cy4A/3YyAP/PuKP//////////////////////////////////////////////////////9K7qP94NQD/ciwA/4VJAP+CRAD/fkEA/35BAP+LSwD/mlYA6v///wD///8A////AP///wDdpnL/4qx3/8KJUv+PUhf/cTMA/3AsAP90LgD/4dK+/////////////////////////////////////////////////////////////////+TYxf91MAD/dTIA/31CAP+GRwD/llQA/6FcAP+gWwD8////AP///wD///8A////ANGZY/LSm2X/4ap3/92mcP+wdT3/byQA/8mwj////////////////////////////////////////////////////////////////////////////+LYxv9zLgP/jUoA/59bAP+hXAD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/RmWL/1p9q/9ubXv/XqXj////////////////////////////7+fD/vZyG/6BxS/+gcUr/vJuE//r37f//////////////////////3MOr/5dQBf+dVQD/nVkA/5xYAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmWP/yohJ//jo2P//////////////////////4NTG/4JDFf9lGAD/bSQA/20kAP9kGAD/fz8S/+Xb0f//////5NG9/6txN/+LOgD/m1QA/51aAP+cWAD/m1cA/5xYAP+cWADy////AP///wD///8A////ANKaZPLSmmT/0ppk/8+TWf/Unmv//v37//////////////////////+TWRr/VwsA/35AAP+ERgD/g0UA/4JGAP9lHgD/kFga/8KXX/+TRwD/jT4A/49CAP+VTQD/n10A/5xYAP+OQQD/lk4A/55cAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/y4tO/92yiP//////////////////////8NnE/8eCQP+rcTT/ez0A/3IyAP98PgD/gEMA/5FSAP+USwD/jj8A/5lUAP+JNwD/yqV2/694Mf+HNQD/jkAA/82rf/+laBj/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/LiUr/4byY///////////////////////gupX/0I5P/+Wuev/Lklz/l1sj/308AP+QSwD/ol0A/59aAP+aVQD/k0oA/8yoh///////+fXv/6pwO//Lp3v///////Pr4f+oay7y////AP///wD///8A////ANKaZPLSmmT/0ppk/8uJSv/hvJj//////////////////////+G7l//Jhkb/0ppk/96nc//fqXX/x4xO/6dkFP+QSQD/llEA/5xXAP+USgD/yaOA///////38uv/qG05/8ijdv//////8efb/6ZpLPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/zIxO/9yxh///////////////////////7dbA/8iEQf/Sm2X/0Zlj/9ScZv/eqHf/2KJv/7yAQf+XTgD/iToA/5lSAP+JNgD/yKFv/611LP+HNQD/jT8A/8qmeP+kZRT/jT4A8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/Pk1n/1J5q//78+//////////////////+/fv/1aFv/8iEQv/Tm2b/0ppl/9GZY//Wn2z/1pZc/9eldf/Bl2b/kUcA/4w9AP+OQAD/lUwA/59eAP+cWQD/jT8A/5ZOAP+eXADy////AP///wD///8A////ANKaZPLSmmT/0ppk/9KZY//KiEn/8d/P///////////////////////47+f/05tm/8iCP//KiEj/yohJ/8eCP//RmGH//vfy///////n1sP/rXQ7/4k4AP+TTAD/nVoA/5xYAP+cVwD/nFgA/5xYAPL///8A////AP///wD///8A0ppk8tKaZP/SmmT/0ptl/8uLTf/aq37////////////////////////////+/fz/6c2y/961jv/etY7/6Myx//78+v//////////////////////3MWv/5xXD/+ORAD/mFQA/51ZAP+cWAD/nFgA8v///wD///8A////AP///wDSmmTy0ppk/9KaZP/SmmT/0ppk/8mFRP/s1b//////////////////////////////////////////////////////////////////////////////+PD/0JFU/7NzMv+WUQD/kUsA/5tXAP+dWQDy////AP///wD///8A////ANKaZP/SmmT/0ppk/9KaZP/Sm2X/z5NZ/8yMT//z5NX/////////////////////////////////////////////////////////////////9Ofa/8yNUP/UmGH/36p5/8yTWv+qaSD/kksA/5ROAPz///8A////AP///wD///8A0ppk5NKaZP/SmmT/0ppk/9KaZP/TnGf/zY9T/82OUv/t1sD//////////////////////////////////////////////////////+7Yw//OkFX/zI5R/9OcZ//SmmP/26V0/9ymdf/BhUf/ol8R6P///wD///8A////AP///wDSmmQ80ppk9tKaZP/SmmT/0ppk/9KaZP/TnGj/zpFW/8qJSv/dson/8uHS//////////////////////////////////Lj0//etIv/y4lL/86QVf/TnGj/0ppk/9KaZP/RmWP/05xn/9ymdfjUnWdC////AP///wD///8A////ANKaZADSmmQc0ppkotKaZP/SmmT/0ppk/9KaZP/Tm2b/0Zli/8qJSf/NjlH/16Z3/+G8mP/myKr/5siq/+G8mP/Xp3f/zY5S/8qISf/RmGH/05tm/9KaZP/SmmT/0ppk/9KaZP/SmmSm0pljINWdaQD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkQtKaZMrSmmT/0ppk/9KaZP/SmmT/0ptl/9GYYf/Nj1P/y4lL/8qISP/KiEj/y4lK/82PU//RmGH/0ptl/9KaZP/SmmT/0ppk/9KaZP/SmmTO0ppkRtKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZGzSmmTu0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmTw0ppkcNKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZBLSmmSQ0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppklNKaZBTSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP///wD///8A0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQy0ppkutKaZP/SmmT/0ppk/9KaZP/SmmT/0ppk/9KaZP/SmmT/0ppkvtKaZDbSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkAP///wD///8A////AP///wDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkXNKaZODSmmT/0ppk/9KaZP/SmmT/0ppk5NKaZGDSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA////AP///wD///8A////ANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkBtKaZIbSmmTo0ppk6tKaZIrSmmQK0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZADSmmQA0ppkANKaZAD///8A////AP/8P///+B///+AH//+AAf//AAD//AAAP/AAAA/gAAAHwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA8AAAAPAAAADwAAAA+AAAAfwAAAP/AAAP/8AAP//gAH//+AH///4H////D//" rel="icon" />
  
  <!--[if lt IE 9]>
    <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
  <![endif]-->
</head>
<body>
<div class="wrapper">
<header id="title-block-header">
<h1 class="title" style="text-align:center">Reconsider parallel <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code>
and <code class="sourceCode cpp">ranges<span class="op">::</span>reverse_copy</code></h1>
<table style="border:none;float:right">
  <tr>
    <td>Document #:</td>
    <td>
      P3709R2
      [<a href="https://wg21.link/P3709">Latest</a>]
      [<a href="https://wg21.link/P3709/status">Status</a>]
    </td>
  </tr>
  <tr>
    <td>Date:</td>
    <td>2025-06-18</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Project:</td>
    <td>Programming Language C++</td>
  </tr>
  <tr>
    <td style="vertical-align:top">Audience:</td>
    <td>
      LEWG<br>
    </td>
  </tr>
  <tr>
    <td style="vertical-align:top">Reply-to:</td>
    <td>
      Ruslan Arutyunyan<br>&lt;<a href="mailto:ruslan.arutyunyan@intel.com" class="email">ruslan.arutyunyan@intel.com</a>&gt;<br>
      Alexey Kukanov<br>&lt;<a href="mailto:alexey.kukanov@intel.com" class="email">alexey.kukanov@intel.com</a>&gt;<br>
    </td>
  </tr>
</table>
</header>
<div style="clear:both">
<div id="TOC" role="doc-toc">
<h1 id="toctitle">Contents</h1>
<ul>
<li><a href="#introduction" id="toc-introduction"><span class="toc-section-number">1</span> Introduction<span></span></a></li>
<li><a href="#rotate_copy_design" id="toc-rotate_copy_design"><span class="toc-section-number">2</span>
<code class="sourceCode cpp">rotate_copy</code> recommended
design<span></span></a></li>
<li><a href="#reverse_copy_design" id="toc-reverse_copy_design"><span class="toc-section-number">3</span>
<code class="sourceCode cpp">reverse_copy</code> recommended
design<span></span></a></li>
<li><a href="#return_type_naming" id="toc-return_type_naming"><span class="toc-section-number">4</span> Return types naming
consideration<span></span></a></li>
<li><a href="#alternative_design" id="toc-alternative_design"><span class="toc-section-number">5</span> Alternative
design<span></span></a></li>
<li><a href="#wording" id="toc-wording"><span class="toc-section-number">6</span> Wording<span></span></a>
<ul>
<li><a href="#modify_alg_syn" id="toc-modify_alg_syn"><span class="toc-section-number">6.1</span> Modify
<span><span>[algorithm.syn]</span></span><span></span></a></li>
<li><a href="#modify_reverse" id="toc-modify_reverse"><span class="toc-section-number">6.2</span> Modify
<span><span>[alg.reverse]</span></span><span></span></a></li>
<li><a href="#modify_rotate" id="toc-modify_rotate"><span class="toc-section-number">6.3</span> Modify
<span><span>[alg.rotate]</span></span><span></span></a></li>
</ul></li>
<li><a href="#revision_history" id="toc-revision_history"><span class="toc-section-number">7</span> Revision history<span></span></a>
<ul>
<li><a href="#r1_r2" id="toc-r1_r2"><span class="toc-section-number">7.1</span> R1 =&gt; R2<span></span></a></li>
<li><a href="#r0_r1" id="toc-r0_r1"><span class="toc-section-number">7.2</span> R0 =&gt; R1<span></span></a></li>
</ul></li>
<li><a href="#polls" id="toc-polls"><span class="toc-section-number">8</span> Polls<span></span></a>
<ul>
<li><a href="#sg9_sofia_2025" id="toc-sg9_sofia_2025"><span class="toc-section-number">8.1</span> SG9, Sofia,
2025<span></span></a></li>
<li><a href="#lewg_sofia_2025" id="toc-lewg_sofia_2025"><span class="toc-section-number">8.2</span> LEWG, Sofia,
2025<span></span></a></li>
</ul></li>
<li><a href="#acknowledgments" id="toc-acknowledgments"><span class="toc-section-number">9</span>
Acknowledgements<span></span></a></li>
<li><a href="#bibliography" id="toc-bibliography"><span class="toc-section-number">10</span> References<span></span></a></li>
</ul>
</div>
<h1 class="unnumbered unlisted" id="abstract">Abstract<a href="#abstract" class="self-link"></a></h1>
<p>This paper proposes changing the return value type for parallel <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code>
and <code class="sourceCode cpp">ranges<span class="op">::</span>reverse_copy</code>
in <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>.</p>
<h1 data-number="1" id="introduction"><span class="header-section-number">1</span> Introduction<a href="#introduction" class="self-link"></a></h1>
<p>LEWG approved the “range-as-the-output” design aspect for our
parallel range algorithms proposal <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>. It introduces the use of a
range with its own bound as the output sequence, taking into account
that the output size may be less than the input size. A common questions
for such algorithms is which iterator to return for the input when the
output size is not sufficient to hold the processed data?</p>
<p>For most cases the answer is pretty simple: we return the iterator
which points to the position right after the last processed element, or
<em>one past the last</em>. Consider <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>copy</code>
as an example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector input<span class="op">{</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span><span class="op">}</span>;</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> output<span class="op">(</span><span class="dv">5</span><span class="op">)</span>; <span class="co">// output with sufficient size</span></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> smaller_output<span class="op">(</span><span class="dv">3</span><span class="op">)</span>; <span class="co">// output with insufficient size</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res1 <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par, input, output<span class="op">)</span>;</span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="co">// after copy invocation res1.in == input.end() is true</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res2 <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>copy<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par, input, smaller_output<span class="op">)</span>;</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="co">// after copy invocation res2.in == input.begin() + 3 is true</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="co">// res2.in points to the element equal to 4</span></span></code></pre></div>
<p>It gives us consistent behavior with serial range algorithms when the
output size is sufficient, and returns the <em>stop point</em> in the
input when the output size is insufficient.</p>
<p>The proposed design in <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> follows the same logic
(returning the stop point for the input) for parallel <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code>
and <code class="sourceCode cpp">ranges<span class="op">::</span>reverse_copy</code>,
and both algorithms use the same return type as their serial range
counterparts. It’s consistent with the rest of the parallel range
algorithms that have an output. However, it leads to interesting
consequences:</p>
<ul>
<li><code class="sourceCode cpp">reverse_copy</code> goes in the reverse
order, so the one past the last iterator for the input never equals to
<code class="sourceCode cpp">last</code>, unless the output range is
empty.</li>
<li><code class="sourceCode cpp">rotate_copy</code> goes over two
subranges within the input range, starting from
<code class="sourceCode cpp">middle</code>. The one past the last
iterator for the input also never equals to
<code class="sourceCode cpp">last</code>: it’s one of the iterators in
either <code class="sourceCode cpp"><span class="op">[</span>middle, last <span class="op">-</span> <span class="dv">1</span><span class="op">]</span></code>
or <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">]</span></code>.</li>
</ul>
<p>The proposed design in <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> allows users to know where the
algorithm stops if the output size is not sufficient to hold all the
elements from the input. The potential problem, however, comes from the
combinations of three factors:</p>
<ul>
<li>in that design, the return type for serial and parallel range
algorithms is the same.</li>
<li>serial range algorithms always return
<code class="sourceCode cpp">last</code> for both
<code class="sourceCode cpp">reverse_copy</code> and
<code class="sourceCode cpp">rotate_copy</code>, however parallel range
algorithms return a different iterator (as explained above) even if the
output size is sufficient.</li>
<li>we envision serial range algorithms with “range-as-the-output”
design in the future, where it is appropriate to return both the
<em>stop point</em> and <code class="sourceCode cpp">last</code>, if it
was calculated.</li>
</ul>
<p>To elaborate more on serial range algorithms: the current strategy
for the vast majority of them is returning as much calculated data as
possible. For example, <code class="sourceCode cpp">ranges<span class="op">::</span>for_each</code>
returns the iterator equal to <code class="sourceCode cpp">last</code>
because that is what the algorithm calculated besides applying a
callable object element-wise. This is useful information because users
might not have such an iterator before the algorithm call; they might
only have a sentinel.</p>
<p>Furthermore, in the future we expect serial range algorithms with
“range-as-the-output” that support not only
<code class="sourceCode cpp">random_access_iterator</code>. For such
algorithms it totally makes sense to return both the input <em>stop
point</em> and the input <code class="sourceCode cpp">last</code>, if
the latter was calculated. For the vast majority of algorithms with the
output, the input <code class="sourceCode cpp">last</code> either cannot
be calculated (when the output size is insufficient) or matches the stop
point. For <code class="sourceCode cpp">reverse_copy</code> and
<code class="sourceCode cpp">rotate_copy</code> this is not true. We
need to keep that in mind when designing these algorithms, because it
would be very unfortunate if serial “range-as-the-output” algorithms end
up returning something different from parallel ones. Thus, the design of
the parallel range algorithms needs to accept that they should return
more information for <code class="sourceCode cpp">random_access_<span class="op">&lt;</span>iterator<span class="op">|</span>range<span class="op">&gt;</span></code>
than seems necessary.</p>
<p>One of the design goals for <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> is to keep the same return
type for the proposed algorithms compared to existing range algorithms,
where possible. However, there is a clear indication that we need to do
something different for <code class="sourceCode cpp">reverse_copy</code>
and <code class="sourceCode cpp">rotate_copy</code>.</p>
<h1 data-number="2" id="rotate_copy_design"><span class="header-section-number">2</span>
<code class="sourceCode cpp">rotate_copy</code> recommended design<a href="#rotate_copy_design" class="self-link"></a></h1>
<p>In <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>
<code class="sourceCode cpp">rotate_copy</code> returns the iterator
past the last copied element for the input. By design, it never returns
<code class="sourceCode cpp">last</code>, and it returns
<code class="sourceCode cpp">middle</code> for two scenarios:</p>
<ul>
<li>the output size is sufficient to copy everything from the
input.</li>
<li>the output range is empty.</li>
</ul>
<p>The raised concern is that users might be surprised at runtime by a
completely different return value after switching to parallel execution.
Moreover, the actual reason for the different value is not an execution
policy but the way how the output range is passed in, which might be
viewed as a purely syntactical modification. Consider the following
example:</p>
<table>
<caption><blockquote>
<p>Variations of <code class="sourceCode cpp">rotate_copy</code></p>
</blockquote></caption>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>iterator-as-the-output</strong>
</div></th>
<th><div style="text-align:center">
<strong>range-as-the-output</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb2"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>list in<span class="op">{</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span><span class="op">}</span>;</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> out<span class="op">(</span><span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">// in_view is not common_range</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> in_view <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>counted<span class="op">(</span>in<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(!</span>std<span class="op">::</span>ranges<span class="op">::</span>common_range<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>in_view<span class="op">)&gt;)</span>;</span>
<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> middle <span class="op">=</span> in_view<span class="op">.</span>begin<span class="op">()</span>;</span>
<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>advance<span class="op">(</span>middle, <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="co">// iterator as the output</span></span>
<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy<span class="op">(</span>in_view, middle, out<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="co">// res.in compares equal to in_view.end()</span></span>
<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> val <span class="op">=</span> std<span class="op">::</span>reduce<span class="op">(</span>in_view<span class="op">.</span>begin<span class="op">()</span>, res<span class="op">.</span>in<span class="op">)</span>;</span>
<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="co">// val is 21</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb3"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>list in<span class="op">{</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span><span class="op">}</span>;</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> out<span class="op">(</span><span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">// in_view is not common_range</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> in_view <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>counted<span class="op">(</span>in<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(!</span>std<span class="op">::</span>ranges<span class="op">::</span>common_range<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>in_view<span class="op">)&gt;)</span>;</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> middle <span class="op">=</span> in_view<span class="op">.</span>begin<span class="op">()</span>;</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>ranges<span class="op">::</span>advance<span class="op">(</span>middle, <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="co">// range as the output</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy<span class="op">(</span>in_view, middle, out<span class="op">)</span>;</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a><span class="co">// res.in equals to middle</span></span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> val <span class="op">=</span> std<span class="op">::</span>reduce<span class="op">(</span>in_view<span class="op">.</span>begin<span class="op">()</span>, res<span class="op">.</span>in<span class="op">)</span>;</span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a><span class="co">// val is 6</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>Please note, that in the table above we don’t use algorithm overloads
with execution policy. Instead, we show the future serial range
algorithms with “range-as-the-output”. That’s because we want to use a
non-<code class="sourceCode cpp">common_range</code>,
non-<code class="sourceCode cpp">random_access_range</code>, so that
calculating <code class="sourceCode cpp">last</code> would make sense.
Parallel range algorithms require
<code class="sourceCode cpp">random_access_range</code>, so the code
would fail to compile if written with execution policy.</p>
<p>While we could address the concern for
<code class="sourceCode cpp">rotate_copy</code> if we jump to the end to
return <code class="sourceCode cpp">last</code> when the output size is
sufficient, there would be two problems with that approach:</p>
<ul>
<li>it is inconsistent with other “range-as-the-output” algorithms which
return the stop point iterator.</li>
<li>we may calculate <code class="sourceCode cpp">last</code> as the
iterator but still not return it, if the output size is insufficient.
See <a href="#introduction">Introduction</a> for more information.</li>
</ul>
<p>So, if we don’t want to surprise users with the different behavior of
parallel <code class="sourceCode cpp">rotate_copy</code> at runtime, we
need to make the code fail to compile when the returned value for the
existing <code class="sourceCode cpp">rotate_copy</code> is stored and
used. We think that users likely store the return value from range
algorithms as
<code class="sourceCode cpp"><span class="kw">auto</span></code> type,
so the names of the publicly accessible fields should also be different
for the result type of the “range-as-the-output”
<code class="sourceCode cpp">rotate_copy</code>.</p>
<p>Since <code class="sourceCode cpp">rotate_copy</code> “swaps” two
subranges - from <code class="sourceCode cpp">middle</code> to
<code class="sourceCode cpp">last</code> and from
<code class="sourceCode cpp">first</code> to
<code class="sourceCode cpp">middle</code> - we want to tell how far the
algorithm progressed for both of them, thus we propose to change the
result type to “alias-ed” <code class="sourceCode cpp">ranges<span class="op">::</span>in_in_out_result</code>.
Its first data member, <code class="sourceCode cpp">in1</code>, contains
one past the last processed iterator for <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>,
which is either the stop point or equals to
<code class="sourceCode cpp">last</code> if this subrange was fully
copied. Similarly, <code class="sourceCode cpp">in2</code> contains one
past the last processed iterator for <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>,
which might equal to <code class="sourceCode cpp">first</code> if the
processing has not reached this subrange, otherwise it is the stop point
up to and including <code class="sourceCode cpp">middle</code>.</p>
<p>We could introduce some new structure because currently
<code class="sourceCode cpp">in_in_out_result</code> is only used for
the algorithms with two input ranges. However, we don’t see a reason to
introduce yet another type since we think that
<code class="sourceCode cpp">in_in_out_result</code> is perfectly
applicable for the discovered use case.</p>
<p>The updated signatures for parallel <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code>
are:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> In, <span class="kw">class</span> Out<span class="op">&gt;</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> rotate_copy_truncated_result <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>in_in_out_result<span class="op">&lt;</span>In, In, Out<span class="op">&gt;</span>;</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S,</span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>        random_access_iterator O, sized_sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>rotate_copy_truncated_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>rotate_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, I first, I middle, S last, O result, OutS result_last<span class="op">)</span>;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR<span class="op">&gt;</span></span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>rotate_copy_truncated_result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>rotate_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, R<span class="op">&amp;&amp;</span> r, iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> middle, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span>;</span></code></pre></div>
<p>In our opinion, the design above addresses all the concerns
because:</p>
<ul>
<li>in <code class="sourceCode cpp">in_out_result</code> the data member
for input is named <code class="sourceCode cpp">in</code> , while in
<code class="sourceCode cpp">in_in_out_result</code> the names for input
are <code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code>, so we achieve the goal for the
code to fail to compile when one uses the output and switches to the
parallel overload, even if users store the result as
<code class="sourceCode cpp"><span class="kw">auto</span></code> type
(but see a caveat below).</li>
<li>it takes into account future serial range algorithms with
“range-as-the-output”, for which
<code class="sourceCode cpp">rotate_copy</code> returns
<ul>
<li>both <code class="sourceCode cpp">last</code>, calculated as an
iterator, and <code class="sourceCode cpp">middle</code> as the stop
point, when the output size is sufficient,</li>
<li>the stop points in both subranges (from
<code class="sourceCode cpp">middle</code> to
<code class="sourceCode cpp">last</code> and from
<code class="sourceCode cpp">first</code> to
<code class="sourceCode cpp">middle</code>) when the output size is less
than the input one.</li>
</ul></li>
</ul>
<p>A possible implementation of the envisioned serial algorithm:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> rotate_copy_fn</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span>forward_iterator I, std<span class="op">::</span>sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S, std<span class="op">::</span>forward_iterator O, std<span class="op">::</span>sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> std<span class="op">::</span>indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy_truncated_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">()(</span>I first, I middle, S last, O result, OutS result_last<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">while</span> <span class="op">(</span>middle <span class="op">!=</span> last <span class="op">&amp;&amp;</span> result <span class="op">!=</span> result_last<span class="op">)</span></span>
<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a>            <span class="op">*</span>result <span class="op">=</span> <span class="op">*</span>middle;</span>
<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a>            <span class="op">++</span>middle;</span>
<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>            <span class="op">++</span>result;</span>
<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a>        <span class="cf">while</span> <span class="op">(</span>first <span class="op">!=</span> middle <span class="op">&amp;&amp;</span> result <span class="op">!=</span> result_last<span class="op">)</span></span>
<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a>            <span class="op">*</span>result <span class="op">=</span> <span class="op">*</span>first;</span>
<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>            <span class="op">++</span>first;</span>
<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a>            <span class="op">++</span>result;</span>
<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">{</span>std<span class="op">::</span>move<span class="op">(</span>middle<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>first<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>result<span class="op">)}</span>;</span>
<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>forward_range R, std<span class="op">::</span>ranges<span class="op">::</span>forward_range OutR<span class="op">&gt;</span></span>
<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> std<span class="op">::</span>indirectly_copyable<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, std<span class="op">::</span>ranges<span class="op">::</span>iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy_truncated_result<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, std<span class="op">::</span>ranges<span class="op">::</span>borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">()(</span>R<span class="op">&amp;&amp;</span> r, std<span class="op">::</span>ranges<span class="op">::</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> middle, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">(*</span><span class="kw">this</span><span class="op">)(</span>std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>middle<span class="op">)</span>,</span>
<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a>                       std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>result_r<span class="op">)</span>, std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>result_r<span class="op">))</span>;</span>
<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> rotate_copy_fn rotate_copy<span class="op">{}</span>;</span></code></pre></div>
<p>Please note that we propose the following order for returned
iterators:</p>
<ul>
<li><code class="sourceCode cpp">in1</code> as a stop point in
[<code class="sourceCode cpp">middle</code>,
<code class="sourceCode cpp">last</code>].</li>
<li><code class="sourceCode cpp">in2</code> as a stop point in
[<code class="sourceCode cpp">first</code>,
<code class="sourceCode cpp">middle</code>].</li>
</ul>
<p>Even though both belong to the same input range, those are just stop
points in two subranges, so we don’t want users to think of them as of a
valid <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>subrange</code>.</p>
<p>Caveat: Since C++26 we can imagine a code that compiles for both
serial range algorithms and the parallel ones even with the proposed
design in this paper, because of structured binding with a pack (<span class="citation" data-cites="P1061R10"><a href="https://wg21.link/p1061r10" role="doc-biblioref">[P1061R10]</a></span>).</p>
<p>Let’s compare:</p>
<table>
<caption><blockquote>
<p>Store the <code class="sourceCode cpp">rotate_copy</code> result to a
structured binding with a pack</p>
</blockquote></caption>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>Serial <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code></strong>
</div></th>
<th><div style="text-align:center">
<strong>Parallel <code class="sourceCode cpp">ranges<span class="op">::</span>rotate_copy</code>
with the proposed design</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb6"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> OutR<span class="op">&gt;</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>R<span class="op">&amp;&amp;</span> in, OutR<span class="op">&amp;&amp;</span> out<span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> middle <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>in<span class="op">)</span>;</span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>advance<span class="op">(</span>middle, <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// possibly to ignore rest...</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>in_last, <span class="op">...</span>rest<span class="op">]</span> <span class="op">=</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy<span class="op">(</span>in, middle, std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>out<span class="op">))</span>;</span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// sizeof...(rest) == 1</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// in_last equals to ranges::end(in)</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb7"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">typename</span> R, <span class="kw">typename</span> OutR<span class="op">&gt;</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="dt">void</span> foo<span class="op">(</span>R<span class="op">&amp;&amp;</span> in, OutR<span class="op">&amp;&amp;</span> out<span class="op">)</span> <span class="op">{</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> middle <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>in<span class="op">)</span>;</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>    std<span class="op">::</span>advance<span class="op">(</span>middle, <span class="dv">3</span><span class="op">)</span>;</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>    <span class="co">// possibly to ignore rest...</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>    <span class="kw">auto</span> <span class="op">[</span>in_last, <span class="op">...</span>rest<span class="op">]</span> <span class="op">=</span></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>        std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy<span class="op">(</span>std<span class="op">::</span>execution<span class="op">::</span>par, in, middle, out<span class="op">)</span>;</span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>    <span class="co">// with this paper, sizeof...(rest) == 2</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>    <span class="co">// in_last equals to ranges::end(in) if the output size is sufficient</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>We can imagine such code if people want to only store the first or
the last data member of the returned object and ignore the rest. With
the code shown above it’s even more important that
<code class="sourceCode cpp">in1</code> is a stop point in
[<code class="sourceCode cpp">middle</code>,
<code class="sourceCode cpp">last</code>] because, assuming that the
size of <code class="sourceCode cpp">out</code> is sufficient for the
whole input, this code compiles and works at runtime as expected. The
same can be said if the structured binding is written as <code class="sourceCode cpp"><span class="kw">auto</span> <span class="op">[...</span>rest, out_last<span class="op">]</span></code>
to get the iterator to the output.</p>
<h1 data-number="3" id="reverse_copy_design"><span class="header-section-number">3</span>
<code class="sourceCode cpp">reverse_copy</code> recommended design<a href="#reverse_copy_design" class="self-link"></a></h1>
<p>For <code class="sourceCode cpp">reverse_copy</code> the proposed
algorithm in <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> always returns the iterator to
the last copied element (in the reversed order) for the input. There is
no “dual meaning” for that returned iterator. In isolation it seems
perfectly fine, however two concerns come in mind:</p>
<ul>
<li>different behavior at runtime compared to the serial counterpart
(which always returns <code class="sourceCode cpp">last</code>), when
the output size is sufficient.</li>
<li>for the envisioned serial <code class="sourceCode cpp">ranges<span class="op">::</span>reverse_copy</code>
with “range-as-the-output” we would calculate
<code class="sourceCode cpp">last</code> as the iterator but not return
that. See <a href="#introduction">Introduction</a> for more
information.</li>
</ul>
<p>Consider the following example:</p>
<table>
<caption><blockquote>
<p>Variations of <code class="sourceCode cpp">reverse_copy</code></p>
</blockquote></caption>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>iterator-as-the-output
<code class="sourceCode cpp">reverse_copy</code></strong>
</div></th>
<th><div style="text-align:center">
<strong>range-as-the-output
<code class="sourceCode cpp">reverse_copy</code></strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td><div>

<div class="sourceCode" id="cb8"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>list in<span class="op">{</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span><span class="op">}</span>;</span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> out<span class="op">(</span><span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="co">// in_view is not common_range</span></span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> in_view <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>counted<span class="op">(</span>in<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(!</span>std<span class="op">::</span>ranges<span class="op">::</span>common_range<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>in_view<span class="op">)&gt;)</span>;</span>
<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a><span class="co">// iterator as the output</span></span>
<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy<span class="op">(</span>in_view, out<span class="op">.</span>begin<span class="op">())</span>;</span>
<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a><span class="co">// res.in compares equal to in_view.end()</span></span>
<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> val <span class="op">=</span> std<span class="op">::</span>reduce<span class="op">(</span>view<span class="op">.</span>begin<span class="op">()</span>, res<span class="op">.</span>in<span class="op">)</span>;</span>
<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a><span class="co">// val is 21</span></span></code></pre></div>

</div></td>
<td><div>

<div class="sourceCode" id="cb9"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>list in<span class="op">{</span><span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">3</span>,<span class="dv">4</span>,<span class="dv">5</span>,<span class="dv">6</span><span class="op">}</span>;</span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>std<span class="op">::</span>vector<span class="op">&lt;</span><span class="dt">int</span><span class="op">&gt;</span> out<span class="op">(</span><span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="co">// in_view is not common_range</span></span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> in_view <span class="op">=</span> std<span class="op">::</span>views<span class="op">::</span>counted<span class="op">(</span>in<span class="op">.</span>begin<span class="op">()</span>, <span class="dv">6</span><span class="op">)</span>;</span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true" tabindex="-1"></a><span class="kw">static_assert</span><span class="op">(!</span>std<span class="op">::</span>ranges<span class="op">::</span>common_range<span class="op">&lt;</span><span class="kw">decltype</span><span class="op">(</span>in_view<span class="op">)&gt;)</span>;</span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true" tabindex="-1"></a><span class="co">// range as the output</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> res <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy<span class="op">(</span>in_view, out<span class="op">)</span>;</span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true" tabindex="-1"></a><span class="co">// res.in equals to in_view.begin()</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true" tabindex="-1"></a><span class="kw">auto</span> val <span class="op">=</span> std<span class="op">::</span>reduce<span class="op">(</span>view<span class="op">.</span>begin<span class="op">()</span>, res<span class="op">.</span>in<span class="op">)</span>;</span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true" tabindex="-1"></a><span class="co">// val is 0</span></span></code></pre></div>

</div></td>
</tr>
</tbody>
</table>
<p>Essentially, the story is similar with
<code class="sourceCode cpp">rotate_copy</code>. All the following
ruminations also apply for parallel
<code class="sourceCode cpp">reverse_copy</code>:</p>
<ul>
<li>a new return type vs
<code class="sourceCode cpp">in_in_out_result</code></li>
<li>returning two different points in the input range rather than a
valid <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>subrange</code></li>
<li>use of structured binding with a parameter pack</li>
</ul>
<p>The solution we see is also similar. We propose to return “alias-ed”
<code class="sourceCode cpp">ranges<span class="op">::</span>in_in_out_result</code>:</p>
<ul>
<li><code class="sourceCode cpp">in1</code> is always the iterator equal
to <code class="sourceCode cpp">last</code>.</li>
<li><code class="sourceCode cpp">in2</code> represents the stop point,
as proposed in <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>.</li>
</ul>
<p>The updated signatures for parallel <code class="sourceCode cpp">ranges<span class="op">::</span>reverse_copy</code>
are:</p>
<div class="sourceCode" id="cb10"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span> <span class="op">&lt;</span><span class="kw">class</span> In, <span class="kw">class</span> Out<span class="op">&gt;</span></span>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="kw">using</span> reverse_copy_truncated_result <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>in_in_out_result<span class="op">&lt;</span>In, In, Out<span class="op">&gt;</span>;</span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S,</span>
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a>        random_access_iterator O, sized_sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>reverse_copy_truncated_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, I first, S last, O result, OutS result_last<span class="op">)</span>;</span>
<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR<span class="op">&gt;</span></span>
<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>reverse_copy_truncated_result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, R<span class="op">&amp;&amp;</span> r, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span>;</span></code></pre></div>
<p>A possible implementation of the envisioned serial algorithm:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="kw">struct</span> reverse_copy_fn</span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="op">{</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span>bidirectional_iterator I, std<span class="op">::</span>sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S, std<span class="op">::</span>forward_iterator O, std<span class="op">::</span>sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> std<span class="op">::</span>indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy_truncated_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">()(</span>I first, S last, O result, OutS result_last<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> last_iter <span class="op">=</span> std<span class="op">::</span>ranges<span class="op">::</span>next<span class="op">(</span>first, last<span class="op">)</span>;</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a>        <span class="kw">auto</span> pos <span class="op">=</span> last_iter;</span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>        <span class="cf">while</span> <span class="op">(</span>pos <span class="op">!=</span> first <span class="op">&amp;&amp;</span> result <span class="op">!=</span> result_last<span class="op">)</span></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a>        <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a>            <span class="op">*</span>result <span class="op">=</span> <span class="op">*--</span>pos;</span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></a>            <span class="op">++</span>result;</span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true" tabindex="-1"></a>        <span class="op">}</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">{</span>last_iter, pos, result<span class="op">}</span>;</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-20"><a href="#cb11-20" aria-hidden="true" tabindex="-1"></a>    <span class="kw">template</span><span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>bidirectional_range R, std<span class="op">::</span>ranges<span class="op">::</span>forward_range OutR<span class="op">&gt;</span></span>
<span id="cb11-21"><a href="#cb11-21" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> std<span class="op">::</span>indirectly_copyable<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, std<span class="op">::</span>ranges<span class="op">::</span>iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb11-22"><a href="#cb11-22" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy_truncated_result<span class="op">&lt;</span>std<span class="op">::</span>ranges<span class="op">::</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, std<span class="op">::</span>ranges<span class="op">::</span>borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb11-23"><a href="#cb11-23" aria-hidden="true" tabindex="-1"></a>        <span class="kw">operator</span><span class="op">()(</span>R<span class="op">&amp;&amp;</span> r, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span> <span class="kw">const</span></span>
<span id="cb11-24"><a href="#cb11-24" aria-hidden="true" tabindex="-1"></a>    <span class="op">{</span></span>
<span id="cb11-25"><a href="#cb11-25" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> <span class="op">(*</span><span class="kw">this</span><span class="op">)(</span>std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>,</span>
<span id="cb11-26"><a href="#cb11-26" aria-hidden="true" tabindex="-1"></a>                       std<span class="op">::</span>ranges<span class="op">::</span>begin<span class="op">(</span>result_r<span class="op">)</span>, std<span class="op">::</span>ranges<span class="op">::</span>end<span class="op">(</span>result_r<span class="op">))</span>;</span>
<span id="cb11-27"><a href="#cb11-27" aria-hidden="true" tabindex="-1"></a>    <span class="op">}</span></span>
<span id="cb11-28"><a href="#cb11-28" aria-hidden="true" tabindex="-1"></a><span class="op">}</span>;</span>
<span id="cb11-29"><a href="#cb11-29" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-30"><a href="#cb11-30" aria-hidden="true" tabindex="-1"></a><span class="kw">inline</span> <span class="kw">constexpr</span> reverse_copy_fn reverse_copy<span class="op">{}</span>;</span></code></pre></div>
<h1 data-number="4" id="return_type_naming"><span class="header-section-number">4</span> Return types naming
consideration<a href="#return_type_naming" class="self-link"></a></h1>
<p>The current design for
<code class="sourceCode cpp">rotate_copy</code> returns the stop points
for two subranges - <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>
- in the input. It means that:</p>
<ul>
<li>for the empty output it returns <code class="sourceCode cpp"><span class="op">{</span>middle, first, out<span class="op">}</span></code></li>
<li>for the output that is sufficient to take some elements from <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
it returns <code class="sourceCode cpp"><span class="op">{</span><em>stop_point</em>, first, out<span class="op">}</span></code></li>
<li>for the output that is sufficient to take all elements from <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
it returns <code class="sourceCode cpp"><span class="op">{</span>last, first, out<span class="op">}</span></code></li>
<li>for the output that is sufficient to take all elements from <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
and some elements from <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>
it returns <code class="sourceCode cpp"><span class="op">{</span>last, <em>stop_point</em>, out<span class="op">}</span></code></li>
<li>for the output that is sufficient to take all elements from <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
and all elements from <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>
it returns <code class="sourceCode cpp"><span class="op">{</span>last, middle, out<span class="op">}</span></code></li>
</ul>
<p>There is a specific reason why the design is like that. The users can
easily figure out what elements were not copied from the input without
extra checks. In the current design with the names
<code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code> those uncopied elements are
<code class="sourceCode cpp"><span class="op">[</span>in1, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>in2, middle<span class="op">)</span></code>.</p>
<p>Аor <code class="sourceCode cpp">rotate_copy</code> the alternative
names to <code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code> could be:</p>
<ul>
<li><code class="sourceCode cpp">stop1</code> and
<code class="sourceCode cpp">stop2</code></li>
<li><code class="sourceCode cpp">stop_right</code> and
<code class="sourceCode cpp">stop_left</code></li>
<li><code class="sourceCode cpp">stage1</code> and
<code class="sourceCode cpp">stage2</code></li>
<li>maybe something else along those lines</li>
</ul>
<p>Those names make sense for the current design but are they anyhow
better than <code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code>? In our opinion - not really.
Furthermore, to use them we need to introduce a new type to C++ standard
library, which does not give any more clarity from our perspective.</p>
<p>To conclude, we don’t see a good alternative, compared to what is
already proposed in the paper, in terms of public data member names of
<code class="sourceCode cpp">rotate_copy</code> return type.</p>
<p>For <code class="sourceCode cpp">reverse_copy</code> the reasonably
good alternatives for <code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code> could be:</p>
<ul>
<li><code class="sourceCode cpp">last</code> and
<code class="sourceCode cpp">stop</code></li>
<li><code class="sourceCode cpp">in</code> and
<code class="sourceCode cpp">stop</code></li>
<li><code class="sourceCode cpp">last</code> and
<code class="sourceCode cpp">in</code></li>
</ul>
<p>Then the question is do we really want to introduce a new type to the
C++ standard library for the sake of one algorithm only? Our
recommendation is that we should not do it.</p>
<p>To summarize, we believe that
<code class="sourceCode cpp">in_in_out_result</code> is good enough type
to be used that implies <code class="sourceCode cpp">in1</code> and
<code class="sourceCode cpp">in2</code> names for public data
members.</p>
<h1 data-number="5" id="alternative_design"><span class="header-section-number">5</span> Alternative design<a href="#alternative_design" class="self-link"></a></h1>
<p>There are the following alternatives to the proposed design:</p>
<ul>
<li>Keep the <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> status quo. The concerns are:
<ul>
<li>The different behavior at runtime, when switching the code to
parallel algorithms.</li>
<li>No calculated <code class="sourceCode cpp">last</code> for future
serial range algorithms with “range-as-the-output”.</li>
</ul></li>
<li>Keep <code class="sourceCode cpp">reverse_copy</code> as proposed in
<span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>, return
<code class="sourceCode cpp">last</code> for parallel
<code class="sourceCode cpp">rotate_copy</code> when the output is
sufficient. The concerns are:
<ul>
<li>for <code class="sourceCode cpp">reverse_copy</code> the concerns
from the previous bullets apply.</li>
<li><code class="sourceCode cpp">rotate_copy</code> becomes inconsistent
with other parallel range algorithms with “range-as-the-output” because
it can “jump” to <code class="sourceCode cpp">last</code> instead of
returning the stop point.</li>
<li>The parallel <code class="sourceCode cpp">rotate_copy</code>
calculates <code class="sourceCode cpp">last</code> but does not return
it, so it likely means a different return type for serial
“range-as-the-output” <code class="sourceCode cpp">rotate_copy</code> in
the future.</li>
</ul></li>
</ul>
<p>We think these alternatives would be worse. If this proposal does not
have a consensus, authors’ preference is to remove parallel
<code class="sourceCode cpp">reverse_copy</code> and
<code class="sourceCode cpp">rotate_copy</code> from <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span> and add them later, possibly
together with the serial “range-as-the-output” algorithms.</p>
<h1 data-number="6" id="wording"><span class="header-section-number">6</span> Wording<a href="#wording" class="self-link"></a></h1>
<p>The diff shown below is against <span class="citation" data-cites="P3179R9"><a href="https://isocpp.org/files/papers/P3179R9.html" role="doc-biblioref">[P3179R9]</a></span>.</p>
<h2 data-number="6.1" id="modify_alg_syn"><span class="header-section-number">6.1</span> Modify <span><a href="https://wg21.link/algorithm.syn">[algorithm.syn]</a></span><a href="#modify_alg_syn" class="self-link"></a></h2>
<div>
<div class="sourceCode" id="cb12"><pre class="sourceCode diff"><code class="sourceCode diff"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>namespace ranges {</span>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>  template&lt;class I, class O&gt;</span>
<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a>    using reverse_copy_result = in_out_result&lt;I, O&gt;;</span>
<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="va">+  template&lt;class I, class O&gt;</span></span>
<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="va">+    using reverse_copy_truncated_result = in_in_out_result&lt;I, I, O&gt;;</span></span>
<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>  template&lt;bidirectional_iterator I, sentinel_for&lt;I&gt; S, weakly_incrementable O&gt;</span>
<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;I, O&gt;</span>
<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a>    constexpr reverse_copy_result&lt;I, O&gt;</span>
<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a>      reverse_copy(I first, S last, O result);</span>
<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a>  template&lt;bidirectional_range R, weakly_incrementable O&gt;</span>
<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;iterator_t&lt;R&gt;, O&gt;</span>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a>    constexpr reverse_copy_result&lt;borrowed_iterator_t&lt;R&gt;, O&gt;</span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a>      reverse_copy(R&amp;&amp; r, O result);</span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a>  template&lt;<em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for&lt;I&gt; S,</span>
<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a>            random_access_iterator O, sized_sentinel_for&lt;O&gt; OutS&gt;</span>
<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;I, O&gt;</span>
<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a><span class="st">-    reverse_copy_result&lt;I, O&gt;</span></span>
<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a><span class="va">+    reverse_copy_truncated_result&lt;I, O&gt;</span></span>
<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a>      reverse_copy(Ep&amp;&amp; exec, I first, S last, O result, OutS result_last);    <em>// freestanding-deleted</em></span>
<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a>  template&lt;<em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR&gt;</span>
<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;iterator_t&lt;R&gt;, iterator_t&lt;OutR&gt;&gt;</span>
<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a><span class="st">-    reverse_copy_result&lt;borrowed_iterator_t&lt;R&gt;, borrowed_iterator_t&lt;OutR&gt;&gt;</span></span>
<span id="cb12-25"><a href="#cb12-25" aria-hidden="true" tabindex="-1"></a><span class="va">+    reverse_copy_truncated_result&lt;borrowed_iterator_t&lt;R&gt;, borrowed_iterator_t&lt;OutR&gt;&gt;</span></span>
<span id="cb12-26"><a href="#cb12-26" aria-hidden="true" tabindex="-1"></a>      reverse_copy(Ep&amp;&amp; exec, R&amp;&amp; r, OutR&amp;&amp; result_r);    <em>// freestanding-deleted</em></span>
<span id="cb12-27"><a href="#cb12-27" aria-hidden="true" tabindex="-1"></a>}</span>
<span id="cb12-28"><a href="#cb12-28" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-29"><a href="#cb12-29" aria-hidden="true" tabindex="-1"></a>namespace ranges {</span>
<span id="cb12-30"><a href="#cb12-30" aria-hidden="true" tabindex="-1"></a>  template&lt;class I, class O&gt;</span>
<span id="cb12-31"><a href="#cb12-31" aria-hidden="true" tabindex="-1"></a>    using rotate_copy_result = in_out_result&lt;I, O&gt;;</span>
<span id="cb12-32"><a href="#cb12-32" aria-hidden="true" tabindex="-1"></a><span class="va">+  template&lt;class I, class O&gt;</span></span>
<span id="cb12-33"><a href="#cb12-33" aria-hidden="true" tabindex="-1"></a><span class="va">+    using rotate_copy_truncated_result = in_in_out_result&lt;I, I, O&gt;;</span></span>
<span id="cb12-34"><a href="#cb12-34" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-35"><a href="#cb12-35" aria-hidden="true" tabindex="-1"></a>  template&lt;forward_iterator I, sentinel_for&lt;I&gt; S, weakly_incrementable O&gt;</span>
<span id="cb12-36"><a href="#cb12-36" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;I, O&gt;</span>
<span id="cb12-37"><a href="#cb12-37" aria-hidden="true" tabindex="-1"></a>    constexpr rotate_copy_result&lt;I, O&gt;</span>
<span id="cb12-38"><a href="#cb12-38" aria-hidden="true" tabindex="-1"></a>      rotate_copy(I first, I middle, S last, O result);</span>
<span id="cb12-39"><a href="#cb12-39" aria-hidden="true" tabindex="-1"></a>  template&lt;forward_range R, weakly_incrementable O&gt;</span>
<span id="cb12-40"><a href="#cb12-40" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;iterator_t&lt;R&gt;, O&gt;</span>
<span id="cb12-41"><a href="#cb12-41" aria-hidden="true" tabindex="-1"></a>    constexpr rotate_copy_result&lt;borrowed_iterator_t&lt;R&gt;, O&gt;</span>
<span id="cb12-42"><a href="#cb12-42" aria-hidden="true" tabindex="-1"></a>      rotate_copy(R&amp;&amp; r, iterator_t&lt;R&gt; middle, O result);</span>
<span id="cb12-43"><a href="#cb12-43" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb12-44"><a href="#cb12-44" aria-hidden="true" tabindex="-1"></a>  template&lt;<em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for&lt;I&gt; S,</span>
<span id="cb12-45"><a href="#cb12-45" aria-hidden="true" tabindex="-1"></a>            random_access_iterator O, sized_sentinel_for&lt;O&gt; OutS&gt;</span>
<span id="cb12-46"><a href="#cb12-46" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;I, O&gt;</span>
<span id="cb12-47"><a href="#cb12-47" aria-hidden="true" tabindex="-1"></a><span class="st">-    ranges::rotate_copy_result&lt;I, O&gt;</span></span>
<span id="cb12-48"><a href="#cb12-48" aria-hidden="true" tabindex="-1"></a><span class="va">+    ranges::rotate_copy_truncated_result&lt;I, O&gt;</span></span>
<span id="cb12-49"><a href="#cb12-49" aria-hidden="true" tabindex="-1"></a>      ranges::rotate_copy(Ep&amp;&amp; exec, I first, I middle, S last, O result, OutS result_last);    <em>// freestanding-deleted</em></span>
<span id="cb12-50"><a href="#cb12-50" aria-hidden="true" tabindex="-1"></a>  template&lt;<em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR&gt;</span>
<span id="cb12-51"><a href="#cb12-51" aria-hidden="true" tabindex="-1"></a>    requires indirectly_copyable&lt;iterator_t&lt;R&gt;, iterator_t&lt;OutR&gt;&gt;</span>
<span id="cb12-52"><a href="#cb12-52" aria-hidden="true" tabindex="-1"></a><span class="st">-    ranges::rotate_copy_result&lt;borrowed_iterator_t&lt;R&gt;, borrowed_iterator_t&lt;OutR&gt;&gt;</span></span>
<span id="cb12-53"><a href="#cb12-53" aria-hidden="true" tabindex="-1"></a><span class="va">+    ranges::rotate_copy_truncated_result&lt;borrowed_iterator_t&lt;R&gt;, borrowed_iterator_t&lt;OutR&gt;&gt;</span></span>
<span id="cb12-54"><a href="#cb12-54" aria-hidden="true" tabindex="-1"></a>      ranges::rotate_copy(Ep&amp;&amp; exec, R&amp;&amp; r, iterator_t&lt;R&gt; middle, OutR&amp;&amp; result_r);    <em>// freestanding-deleted</em></span>
<span id="cb12-55"><a href="#cb12-55" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
</div>
<h2 data-number="6.2" id="modify_reverse"><span class="header-section-number">6.2</span> Modify <span><a href="https://wg21.link/alg.reverse">[alg.reverse]</a></span><a href="#modify_reverse" class="self-link"></a></h2>
<div class="sourceCode" id="cb13"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>bidirectional_iterator I, sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S, weakly_incrementable O<span class="op">&gt;</span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> ranges<span class="op">::</span>reverse_copy_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>I first, S last, O result<span class="op">)</span>;</span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>bidirectional_range R, weakly_incrementable O<span class="op">&gt;</span></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, O<span class="op">&gt;</span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> ranges<span class="op">::</span>reverse_copy_result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, O<span class="op">&gt;</span></span>
<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, O result<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">5</a></span>
Let <em><code class="sourceCode cpp">N</code></em> be
<code class="sourceCode cpp">last <span class="op">-</span> first</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
<em>Preconditions</em>: The ranges <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
do not overlap.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Effects</em>: Copies the range <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
to the range <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
such that for every non-negative integer
<code class="sourceCode cpp">i <span class="op">&lt;</span> <em>N</em></code>
the following assignment takes place: <code class="sourceCode cpp"><span class="op">*(</span>result <span class="op">+</span> <em>N</em> <span class="op">-</span> <span class="dv">1</span> <span class="op">-</span> i<span class="op">)</span> <span class="op">=</span> <span class="op">*(</span>first <span class="op">+</span> i<span class="op">)</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Returns</em>:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(8.1)</a></span>
<code class="sourceCode cpp">result <span class="op">+</span> <em>N</em></code>
for the overloads in namespace
<code class="sourceCode cpp">std</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(8.2)</a></span>
<code class="sourceCode cpp"><span class="op">{</span>last, result <span class="op">+</span> <em>N</em><span class="op">}</span></code>
for the overloads in namespace
<code class="sourceCode cpp">ranges</code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Complexity</em>: Exactly
<em><code class="sourceCode cpp">N</code></em> assignments.</p>
<div class="sourceCode" id="cb14"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S,</span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a>         random_access_iterator O, sized_sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>reverse_copy_<span class="add" style="color: #006e28"><ins>truncated_</ins></span>result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, I first, S last, O result, OutS result_last<span class="op">)</span>;</span>
<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR<span class="op">&gt;</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>reverse_copy_<span class="add" style="color: #006e28"><ins>truncated_</ins></span>result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>reverse_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, R<span class="op">&amp;&amp;</span> r, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
Let <em><code class="sourceCode cpp">N</code></em> be
min(<code class="sourceCode cpp">last <span class="op">-</span> first</code>,
<code class="sourceCode cpp">result_last <span class="op">-</span> result</code>),
and let <em><code class="sourceCode cpp">NEW_FIRST</code></em> be <code class="sourceCode cpp">first <span class="op">+</span> <span class="op">(</span>last <span class="op">-</span> first<span class="op">)</span> <span class="op">-</span> <em>N</em></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Preconditions</em>: The ranges <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
do not overlap.</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Effects</em>: Copies the range <code class="sourceCode cpp"><span class="op">[</span><em>NEW_FIRST</em>, last<span class="op">)</span></code>
to the range <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
such that for every non-negative integer
<code class="sourceCode cpp">i <span class="op">&lt;</span> <em>N</em></code>
the following assignment takes place: <code class="sourceCode cpp"><span class="op">*(</span>result <span class="op">+</span> <em>N</em> <span class="op">-</span> <span class="dv">1</span> <span class="op">-</span> i<span class="op">)</span> <span class="op">=</span> <span class="op">*(</span><em>NEW_FIRST</em> <span class="op">+</span> i<span class="op">)</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Returns</em>: <code class="sourceCode cpp">{<span class="add" style="color: #006e28"><ins><span><code class="sourceCode default">last,</code></span></ins></span> <span class="citation" data-cites="*NEW_FIRST"><em>NEW_FIRST</span></em>, <span class="citation" data-cites="result">result</span> + <em>N</em>}</code>.</p>
<p><span class="rm" style="color: #bf0303"><del><span class="note"><span>[ <em>Note:</em> </span>While the return type for the
parallel and non-parallel algorithm overloads in the namespace
<span><code class="sourceCode default">ranges</code></span> is the same
the semantics is different because the parallel range algorithm
overloads
<span><code class="sourceCode default">result_last - result</code></span>
can be insufficient to copy all data from the input.<span> — <em>end
note</em> ]</span></span></del></span></p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Complexity</em>: Exactly
<em><code class="sourceCode cpp">N</code></em> assignments.</p>
<h2 data-number="6.3" id="modify_rotate"><span class="header-section-number">6.3</span> Modify <span><a href="https://wg21.link/alg.rotate">[alg.rotate]</a></span><a href="#modify_rotate" class="self-link"></a></h2>
<div class="sourceCode" id="cb15"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>forward_iterator I, sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S, weakly_incrementable O<span class="op">&gt;</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>    <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>    <span class="kw">constexpr</span> ranges<span class="op">::</span>rotate_copy_result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>      ranges<span class="op">::</span>rotate_copy<span class="op">(</span>I first, I middle, S last, O result<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">6</a></span>
Let <em><code class="sourceCode cpp">N</code></em> be
<code class="sourceCode cpp">last <span class="op">-</span> first</code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">7</a></span>
<em>Preconditions</em>: <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
are valid ranges. The ranges <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
do not overlap.</p>
<p><span class="marginalizedparent"><a class="marginalized">8</a></span>
<em>Effects</em>: Copies the range <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
to the range <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
such that for each non-negative integer
<code class="sourceCode cpp">i <span class="op">&lt;</span> <em>N</em></code>
the following assignment takes place: <code class="sourceCode cpp"><span class="op">*(</span>result <span class="op">+</span> i<span class="op">)</span> <span class="op">=</span> <span class="op">*(</span>first <span class="op">+</span> <span class="op">(</span>i <span class="op">+</span> <span class="op">(</span>middle <span class="op">-</span> first<span class="op">))</span> <span class="op">%</span> <em>N</em><span class="op">)</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">9</a></span>
<em>Returns</em>:</p>
<ul>
<li><span class="marginalizedparent"><a class="marginalized">(9.1)</a></span>
<code class="sourceCode cpp">result <span class="op">+</span> <em>N</em></code>
for the overloads in namespace
<code class="sourceCode cpp">std</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(9.2)</a></span>
<code class="sourceCode cpp"><span class="op">{</span>last, result <span class="op">+</span> <em>N</em><span class="op">}</span></code>
for the overload in namespace
<code class="sourceCode cpp">ranges</code>.</li>
</ul>
<p><span class="marginalizedparent"><a class="marginalized">10</a></span>
<em>Complexity</em>: Exactly
<em><code class="sourceCode cpp">N</code></em> assignments.</p>
<div class="sourceCode" id="cb16"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, random_access_iterator I, sized_sentinel_for<span class="op">&lt;</span>I<span class="op">&gt;</span> S,</span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>         random_access_iterator O, sized_sentinel_for<span class="op">&lt;</span>O<span class="op">&gt;</span> OutS<span class="op">&gt;</span></span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>rotate_copy_<span class="add" style="color: #006e28"><ins>truncated_</ins></span>result<span class="op">&lt;</span>I, O<span class="op">&gt;</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>rotate_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, I first, I middle, S last, O result, OutS result_last<span class="op">)</span>;</span></code></pre></div>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
Let <em><code class="sourceCode cpp">M</code></em> be
<code class="sourceCode cpp">last <span class="op">-</span> first</code>
and <em><code class="sourceCode cpp">N</code></em> be
min(<em><code class="sourceCode cpp">M</code></em>, <code class="sourceCode cpp">result_last <span class="op">-</span> result</code>).</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Preconditions</em>: <code class="sourceCode cpp"><span class="op">[</span>first, middle<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>middle, last<span class="op">)</span></code>
are valid ranges. The ranges <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
and <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
do not overlap.</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Effects</em>: Copies the range <code class="sourceCode cpp"><span class="op">[</span>first, last<span class="op">)</span></code>
to the range <code class="sourceCode cpp"><span class="op">[</span>result, result <span class="op">+</span> <em>N</em><span class="op">)</span></code>
such that for each non-negative integer
<code class="sourceCode cpp">i <span class="op">&lt;</span> <em>N</em></code>
the following assignment takes place: <code class="sourceCode cpp"><span class="op">*(</span>result <span class="op">+</span> i<span class="op">)</span> <span class="op">=</span> <span class="op">*(</span>first <span class="op">+</span> <span class="op">(</span>i <span class="op">+</span> <span class="op">(</span>middle <span class="op">-</span> first<span class="op">))</span> <span class="op">%</span> <em>M</em><span class="op">)</span></code>.</p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Returns</em>:<span class="rm" style="color: #bf0303"><del><span><code class="sourceCode default">{first + (<em>N</em> + (middle - first)) % <em>M</em>, result + <em>N</em>}</code></span>.</del></span></p>
<div class="add" style="color: #006e28">

<ul>
<li><span class="marginalizedparent"><a class="marginalized">(x.1)</a></span>
<code class="sourceCode default">{middle + <em>N</em>, first, result + <em>N</em>}</code>
if <em><code class="sourceCode default">N</code></em> is less than
<code class="sourceCode default">last - middle</code>.</li>
<li><span class="marginalizedparent"><a class="marginalized">(x.2)</a></span>
Otherwise, <code class="sourceCode default">{last, first + (<em>N</em> + (middle - first)) % <em>M</em>, result + <em>N</em>}</code>.</li>
</ul>

</div>
<p><span class="rm" style="color: #bf0303"><del><span class="note"><span>[ <em>Note:</em> </span>While the return type for the
parallel and non-parallel algorithm overloads in the namespace
<span><code class="sourceCode default">ranges</code></span> is the same
the semantics is different because the parallel range algorithm
overloads
<span><code class="sourceCode default">result_last - result</code></span>
can be insufficient to copy all data from the input.<span> — <em>end
note</em> ]</span></span></del></span></p>
<p><span class="marginalizedparent"><a class="marginalized">x</a></span>
<em>Complexity</em>: Exactly
<em><code class="sourceCode cpp">N</code></em> assignments.</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span>forward_range R, weakly_incrementable O<span class="op">&gt;</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, O<span class="op">&gt;</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>  <span class="kw">constexpr</span> ranges<span class="op">::</span>rotate_copy_result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, O<span class="op">&gt;</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>rotate_copy<span class="op">(</span>R<span class="op">&amp;&amp;</span> r, iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> middle, O result<span class="op">)</span>;</span></code></pre></div>
<p><em>Effects</em>: Equivalent to: <code class="sourceCode cpp"><span class="cf">return</span> ranges<span class="op">::</span>rotate_copy<span class="op">(</span>ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>, middle, ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>, std<span class="op">::</span>move<span class="op">(</span>result<span class="op">))</span>;</code></p>
<div class="sourceCode" id="cb18"><pre class="sourceCode cpp"><code class="sourceCode cpp"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">template</span><span class="op">&lt;</span><em>execution-policy</em> Ep, <em>sized-random-access-range</em> R, <em>sized-random-access-range</em> OutR<span class="op">&gt;</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>  <span class="kw">requires</span> indirectly_copyable<span class="op">&lt;</span>iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>  ranges<span class="op">::</span>rotate_copy_<span class="add" style="color: #006e28"><ins>truncated_</ins></span>result<span class="op">&lt;</span>borrowed_iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span>, borrowed_iterator_t<span class="op">&lt;</span>OutR<span class="op">&gt;&gt;</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>    ranges<span class="op">::</span>rotate_copy<span class="op">(</span>Ep<span class="op">&amp;&amp;</span> exec, R<span class="op">&amp;&amp;</span> r, iterator_t<span class="op">&lt;</span>R<span class="op">&gt;</span> middle, OutR<span class="op">&amp;&amp;</span> result_r<span class="op">)</span>;</span></code></pre></div>
<p><em>Effects</em>: Equivalent to: <code class="sourceCode cpp"><span class="cf">return</span> ranges<span class="op">::</span>rotate_copy<span class="op">(</span>std<span class="op">::</span>forward<span class="op">&lt;</span>Ep<span class="op">&gt;(</span>exec<span class="op">)</span>, ranges<span class="op">::</span>begin<span class="op">(</span>r<span class="op">)</span>, middle, ranges<span class="op">::</span>end<span class="op">(</span>r<span class="op">)</span>, ranges<span class="op">::</span>begin<span class="op">(</span>result_r<span class="op">)</span>, ranges<span class="op">::</span>end<span class="op">(</span>result_r<span class="op">))</span>;</code></p>
<h1 data-number="7" id="revision_history"><span class="header-section-number">7</span> Revision history<a href="#revision_history" class="self-link"></a></h1>
<h2 data-number="7.1" id="r1_r2"><span class="header-section-number">7.1</span> R1 =&gt; R2<a href="#r1_r2" class="self-link"></a></h2>
<ul>
<li>Add naming considerations for public data member of
<code class="sourceCode cpp">reverse_copy</code> and
<code class="sourceCode cpp">rotate_copy</code> return types.</li>
</ul>
<h2 data-number="7.2" id="r0_r1"><span class="header-section-number">7.2</span> R0 =&gt; R1<a href="#r0_r1" class="self-link"></a></h2>
<ul>
<li>Editorial changes and fixes</li>
<li>Add the formal wording</li>
</ul>
<h1 data-number="8" id="polls"><span class="header-section-number">8</span> Polls<a href="#polls" class="self-link"></a></h1>
<h2 data-number="8.1" id="sg9_sofia_2025"><span class="header-section-number">8.1</span> SG9, Sofia, 2025<a href="#sg9_sofia_2025" class="self-link"></a></h2>
<p>POLL: We want to change the return type of the parallel <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy</code>
to return both “stop” and “end”, instead of just “stop” (unlike the
serial one where it is “end”).</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>5</td>
<td>3</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>POLL: We want to change the return type of the parallel <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy</code>
to return both “stop” and “end”, instead of just “stop” (unlike the
serial one where it is “end”).</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>4</td>
<td>4</td>
<td>1</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>POLL: We want to use <code class="sourceCode cpp">std<span class="op">::</span>in_in_out_result</code>
as the return type of <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy</code>
and <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy</code>
(as proposed in the paper).</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td>2</td>
<td>4</td>
<td>2</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>POLL: We want to use a new return type with members e.g. <code class="sourceCode cpp"><span class="op">{</span>in_end, in_stop, out<span class="op">}</span></code>
(names TBD) instead of <code class="sourceCode cpp">std<span class="op">::</span>in_in_out_result</code></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>1</td>
<td>3</td>
<td>5</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>POLL: Remove the parallel execution overloads of <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>rotate_copy</code>
and <code class="sourceCode cpp">std<span class="op">::</span>ranges<span class="op">::</span>reverse_copy</code>
from P3179R9 scheduled for C++26.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>3</td>
<td>2</td>
<td>1</td>
<td>3</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>POLL: Forward P3709R1, with the return type change guidance from
above to LEWG for inclusion in C++26.</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>2</td>
<td>6</td>
<td>0</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<h2 data-number="8.2" id="lewg_sofia_2025"><span class="header-section-number">8.2</span> LEWG, Sofia, 2025<a href="#lewg_sofia_2025" class="self-link"></a></h2>
<p>POLL: We want to change the return type of “rotate_copy” and
“reverse_copy” to something similar to in_in_out</p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>3</td>
<td>7</td>
<td>2</td>
<td>0</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>POLL: In P3709R1 rotate_copy and reverse_copy should have a dedicated
return type instead of re-using
<code class="sourceCode cpp">in_in_out_result</code></p>
<table>
<thead>
<tr class="header">
<th><div style="text-align:center">
<strong>SF</strong>
</div></th>
<th><div style="text-align:center">
<strong>F</strong>
</div></th>
<th><div style="text-align:center">
<strong>N</strong>
</div></th>
<th><div style="text-align:center">
<strong>A</strong>
</div></th>
<th><div style="text-align:center">
<strong>SA</strong>
</div></th>
</tr>
</thead>
<tbody>
<tr class="odd">
<td>7</td>
<td>5</td>
<td>2</td>
<td>2</td>
<td>0</td>
</tr>
</tbody>
</table>
<h1 data-number="9" id="acknowledgments"><span class="header-section-number">9</span> Acknowledgements<a href="#acknowledgments" class="self-link"></a></h1>
<ul>
<li>Thanks to Jonathan Mueller for a fruitful discussion on
<code class="sourceCode cpp">reverse_copy</code> and
<code class="sourceCode cpp">rotate_copy</code> return type.</li>
</ul>
<h1 data-number="10" id="bibliography"><span class="header-section-number">10</span> References<a href="#bibliography" class="self-link"></a></h1>
<div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="1" role="doc-bibliography">
<div id="ref-P1061R10" class="csl-entry" role="doc-biblioentry">
[P1061R10] Barry Revzin, Jonathan Wakely. 2024-11-24. Structured
Bindings can introduce a Pack. <a href="https://wg21.link/p1061r10"><div class="csl-block">https://wg21.link/p1061r10</div></a>
</div>
<div id="ref-P3179R9" class="csl-entry" role="doc-biblioentry">
[P3179R9] Ruslan Arutyunyan, Alexey Kukanov, and Bryce Adelstein
Lelbach. C++ parallel range algorithms. <a href="https://isocpp.org/files/papers/P3179R9.html"><div class="csl-block">https://isocpp.org/files/papers/P3179R9.html</div></a>
</div>
</div>
</div>
</div>
</body>
</html>
