|
| 1 | +\documentclass[a4paper,10pt,oneside,openany,final,article]{memoir} |
| 2 | +\input{common} |
| 3 | +\settocdepth{chapter} |
| 4 | +\usepackage{minted} |
| 5 | +\usepackage{fontspec} |
| 6 | + |
| 7 | +\begin{document} |
| 8 | +\title{Optimize for std::optional in range adaptors} |
| 9 | +\author{ |
| 10 | + Steve Downey \small<\href{mailto:sdowney@gmail.com}{sdowney@gmail.com}> \\ |
| 11 | + Tomasz Kamiński \small<\href{mailto:tomaszkam@gmail.com}{tomaszkam@gmail.com}> \\ |
| 12 | +} |
| 13 | +\date{} %unused. Type date explicitly below. |
| 14 | +\maketitle |
| 15 | + |
| 16 | +\begin{flushright} |
| 17 | + \begin{tabular}{ll} |
| 18 | + Document \#: & P3913R1 \\ |
| 19 | + Date: & \today \\ |
| 20 | + Project: & Programming Language C++ \\ |
| 21 | + Audience: & LWG |
| 22 | + \end{tabular} |
| 23 | +\end{flushright} |
| 24 | + |
| 25 | +\begin{abstract} |
| 26 | +From PL-011 22.5 [optional] Optimize for std::optional in range adaptors |
| 27 | + |
| 28 | +The range support was added to the optional, making it usable with range adaptors defined in std::views, however, we have not updated the views specification to handle it optimally when possible. This leads to unnecessary template instantiations. |
| 29 | + |
| 30 | +\end{abstract} |
| 31 | + |
| 32 | +\tableofcontents* |
| 33 | + |
| 34 | +\chapter{Motivation} |
| 35 | +The range support was added to the optional, making it usable with range adaptors defined in std::views, however, we have not updated the views specification to handle it optimally when possible. This leads to unnecessary template instantiations. |
| 36 | + |
| 37 | +Proposed change: |
| 38 | + |
| 39 | +Add a special case to recognize optional for adaptors: |
| 40 | + |
| 41 | +\begin{itemize} |
| 42 | +\item |
| 43 | +views::as_const: should return optional or optional<const U\&> (if T is U\&) |
| 44 | +\item |
| 45 | +views::take(opt, n): empty optional if n is equal to zero, opt otherwise |
| 46 | +\item |
| 47 | +views::drop(opt, n): empty optional if n greater than zero, opt otherwise |
| 48 | +\item |
| 49 | +views::reverse: input unchanged |
| 50 | +\end{itemize} |
| 51 | + |
| 52 | +\chapter{Design} |
| 53 | + |
| 54 | + |
| 55 | +\section{views::as_const} |
| 56 | + |
| 57 | +Return \tcode{optional}. |
| 58 | + |
| 59 | +In contrast to \tcode{optional<const T\&>}, \tcode{optional<const T>} is not a view, because it is not assignable. In consequence it should not be returned from \tcode{views::as_const} for \tcode{optional<T>}. |
| 60 | +\section{views::take(opt, n)} |
| 61 | + |
| 62 | +Empty \tcode{optional} if \tcode{n} is equal to zero, \tcode{optional} otherwise. |
| 63 | + |
| 64 | +\section{views::drop(opt, n)} |
| 65 | + |
| 66 | +Empty \tcode{optional} if \tcode{n} greater than zero, \tcode{optional} otherwise. |
| 67 | + |
| 68 | +\section{views::reverse} |
| 69 | + |
| 70 | +Input is returned unchanged. |
| 71 | + |
| 72 | +\chapter{Wording} |
| 73 | +The proposed changes are relative to the current working draft \cite{N5014}. |
| 74 | + |
| 75 | + |
| 76 | +\begin{wording} |
| 77 | +\rSec1[ranges.general]{General} |
| 78 | + |
| 79 | +\rSec2[range.take]{Take view} |
| 80 | + |
| 81 | +\rSec3[range.take.overview]{Overview} |
| 82 | + |
| 83 | +\pnum |
| 84 | +\tcode{take_view} produces a view of the first $N$ elements |
| 85 | +from another view, or all the elements if the adapted |
| 86 | +view contains fewer than $N$. |
| 87 | + |
| 88 | +\pnum |
| 89 | +\indexlibrarymember{take}{views}% |
| 90 | +The name \tcode{views::take} denotes a |
| 91 | +range adaptor object\iref{range.adaptor.object}. |
| 92 | +Let \tcode{E} and \tcode{F} be expressions, |
| 93 | +let \tcode{T} be \tcode{remove_cvref_t<decltype((E))>}, and |
| 94 | +let \tcode{D} be \tcode{range_difference_t<decltype((E))>}. |
| 95 | +If \tcode{decltype((F))} does not model |
| 96 | +\tcode{\libconcept{convertible_to}<D>}, |
| 97 | +\tcode{views::take(E, F)} is ill-formed. |
| 98 | +Otherwise, the expression \tcode{views::take(E, F)} |
| 99 | +is expression-equivalent to: |
| 100 | + |
| 101 | +\begin{itemize} |
| 102 | +\item |
| 103 | +If \tcode{T} is a specialization |
| 104 | +of \tcode{empty_view}\iref{range.empty.view}, |
| 105 | +then \tcode{((void)F, \placeholdernc{decay-copy}(E))}, |
| 106 | +except that the evaluations of \tcode{E} and \tcode{F} |
| 107 | +are indeterminately sequenced. |
| 108 | +\begin{addedblock} |
| 109 | +\item |
| 110 | +Otherwise, if \tcode{T} is a specialization of \tcode{optional} and \tcode{T} models \tcode{view}, then \tcode{(static_cast<D>(F) == D() ? ((void)E, T()) : \placeholdernc{decay-copy}(E))}. |
| 111 | +\end{addedblock} |
| 112 | +\item |
| 113 | +Otherwise, if \tcode{T} models |
| 114 | +\libconcept{random_access_range} and \libconcept{sized_range} |
| 115 | +and is a specialization of |
| 116 | +\tcode{span}\iref{views.span}, |
| 117 | +\tcode{basic_string_view}\iref{string.view}, or |
| 118 | +\tcode{subrange}\iref{range.subrange}, |
| 119 | +then |
| 120 | +\tcode{U(ranges::begin(E), |
| 121 | +ranges::be\-gin(E) + std::min<D>(ranges::distance(E), F))}, |
| 122 | +except that \tcode{E} is evaluated only once, |
| 123 | +where \tcode{U} is a type determined as follows: |
| 124 | + |
| 125 | +\begin{itemize} |
| 126 | +\item if \tcode{T} is a specialization of \tcode{span}, |
| 127 | +then \tcode{U} is \tcode{span<typename T::element_type>}; |
| 128 | +\item otherwise, if \tcode{T} is a specialization of \tcode{basic_string_view}, |
| 129 | +then \tcode{U} is \tcode{T}; |
| 130 | +\item otherwise, \tcode{T} is a specialization of \tcode{subrange}, and |
| 131 | +\tcode{U} is \tcode{subrange<iterator_t<T>>}; |
| 132 | +\end{itemize} |
| 133 | + |
| 134 | +\item |
| 135 | +otherwise, if \tcode{T} is |
| 136 | +a specialization of \tcode{iota_view}\iref{range.iota.view} |
| 137 | +that models \libconcept{random_access_range} and \libconcept{sized_range}, |
| 138 | +then |
| 139 | +\tcode{iota_view(*ranges::begin(E), |
| 140 | +*(ranges::begin(E) + std::\linebreak{}min<D>(ranges::distance(E), F)))}, |
| 141 | +except that \tcode{E} is evaluated only once. |
| 142 | + |
| 143 | +\item |
| 144 | +Otherwise, if \tcode{T} is |
| 145 | +a specialization of \tcode{repeat_view}\iref{range.repeat.view}: |
| 146 | +\begin{itemize} |
| 147 | +\item |
| 148 | +if \tcode{T} models \libconcept{sized_range}, |
| 149 | +then |
| 150 | +\begin{codeblock} |
| 151 | +views::repeat(*E.@\exposid{value_}@, std::min<D>(ranges::distance(E), F)) |
| 152 | +\end{codeblock} |
| 153 | +except that \tcode{E} is evaluated only once; |
| 154 | +\item |
| 155 | +otherwise, \tcode{views::repeat(*E.\exposid{value_}, static_cast<D>(F))}. |
| 156 | +\end{itemize} |
| 157 | + |
| 158 | +\item |
| 159 | +Otherwise, \tcode{take_view(E, F)}. |
| 160 | +\end{itemize} |
| 161 | + |
| 162 | +\rSec2[range.drop]{Drop view} |
| 163 | + |
| 164 | +\rSec3[range.drop.overview]{Overview} |
| 165 | + |
| 166 | +\pnum |
| 167 | +\tcode{drop_view} produces a view |
| 168 | +excluding the first $N$ elements from another view, or |
| 169 | +an empty range if the adapted view contains fewer than $N$ elements. |
| 170 | + |
| 171 | +\pnum |
| 172 | +\indexlibrarymember{drop}{views}% |
| 173 | +The name \tcode{views::drop} denotes |
| 174 | +a range adaptor object\iref{range.adaptor.object}. |
| 175 | +Let \tcode{E} and \tcode{F} be expressions, |
| 176 | +let \tcode{T} be \tcode{remove_cvref_t<decltype((E))>}, and |
| 177 | +let \tcode{D} be \tcode{range_difference_t<decltype((E))>}. |
| 178 | +If \tcode{decltype((F))} does not model |
| 179 | +\tcode{\libconcept{convertible_to}<D>}, |
| 180 | +\tcode{views::drop(E, F)} is ill-formed. |
| 181 | +Otherwise, the expression \tcode{views::drop(E, F)} |
| 182 | +is expression-equivalent to: |
| 183 | + |
| 184 | +\begin{itemize} |
| 185 | +\item |
| 186 | +If \tcode{T} is a specialization of |
| 187 | +\tcode{empty_view}\iref{range.empty.view}, |
| 188 | +then \tcode{((void)F, \placeholdernc{decay-copy}(E))}, |
| 189 | +except that the evaluations of \tcode{E} and \tcode{F} |
| 190 | +are indeterminately sequenced. |
| 191 | +\begin{addedblock} |
| 192 | +\item |
| 193 | +Otherwise, if \tcode{T} is a specialization of \tcode{optional} and \tcode{T} models \tcode{view}, then \tcode{(static_cast<D>(F) == D() ? \placeholdernc{decay-copy}(E) : ((void)E, T()))}. |
| 194 | +\end{addedblock} |
| 195 | +\item |
| 196 | +Otherwise, if \tcode{T} models |
| 197 | +\libconcept{random_access_range} and \libconcept{sized_range} |
| 198 | +and is |
| 199 | +\begin{itemize} |
| 200 | +\item a specialization of \tcode{span}\iref{views.span}, |
| 201 | +\item a specialization of \tcode{basic_string_view}\iref{string.view}, |
| 202 | +\item a specialization of \tcode{iota_view}\iref{range.iota.view}, or |
| 203 | +\item a specialization of \tcode{subrange}\iref{range.subrange} |
| 204 | +where \tcode{T::\exposid{StoreSize}} is \tcode{false}, |
| 205 | +\end{itemize} |
| 206 | +then \tcode{U(ranges::begin(E) + std::min<D>(ranges::distance(E), F), ranges::end(E))}, |
| 207 | +except that \tcode{E} is evaluated only once, |
| 208 | +where \tcode{U} is \tcode{span<typename T::element_type>} |
| 209 | +if \tcode{T} is a specialization of \tcode{span} and \tcode{T} otherwise. |
| 210 | + |
| 211 | +\item |
| 212 | +Otherwise, |
| 213 | +if \tcode{T} is |
| 214 | +a specialization of \tcode{subrange} |
| 215 | +that models \libconcept{random_access_range} and \libconcept{sized_range}, |
| 216 | +then |
| 217 | +\tcode{T(ranges::begin(E) + std::min<D>(ranges::distance(E), F), ranges::\linebreak{}end(E), |
| 218 | +\exposid{to-unsigned-like}(ranges::distance(E) - |
| 219 | +std::min<D>(ranges::distance(E), F)))}, |
| 220 | +except that \tcode{E} and \tcode{F} are each evaluated only once. |
| 221 | + |
| 222 | +\item |
| 223 | +Otherwise, if \tcode{T} is |
| 224 | +a specialization of \tcode{repeat_view}\iref{range.repeat.view}: |
| 225 | +\begin{itemize} |
| 226 | +\item |
| 227 | +if \tcode{T} models \libconcept{sized_range}, |
| 228 | +then |
| 229 | +\begin{codeblock} |
| 230 | +views::repeat(*E.@\exposid{value_}@, ranges::distance(E) - std::min<D>(ranges::distance(E), F)) |
| 231 | +\end{codeblock} |
| 232 | +except that \tcode{E} is evaluated only once; |
| 233 | +\item |
| 234 | +otherwise, \tcode{((void)F, \placeholdernc{decay-copy}(E))}, |
| 235 | +except that the evaluations of \tcode{E} and \tcode{F} are indeterminately sequenced. |
| 236 | +\end{itemize} |
| 237 | + |
| 238 | +\item |
| 239 | +Otherwise, \tcode{drop_view(E, F)}. |
| 240 | +\end{itemize} |
| 241 | + |
| 242 | +\rSec2[range.as.const]{As const view} |
| 243 | + |
| 244 | +\rSec3[range.as.const.overview]{Overview} |
| 245 | + |
| 246 | +\pnum |
| 247 | +\tcode{as_const_view} presents a view of an underlying sequence as constant. |
| 248 | +That is, the elements of an \tcode{as_const_view} cannot be modified. |
| 249 | + |
| 250 | +\pnum |
| 251 | +The name \tcode{views::as_const} denotes |
| 252 | +a range adaptor object\iref{range.adaptor.object}. |
| 253 | +Let \tcode{E} be an expression, |
| 254 | +let \tcode{T} be \tcode{decltype((E))}, and |
| 255 | +let \tcode{U} be \tcode{remove_cvref_t<T>}. |
| 256 | +The expression \tcode{views::as_const(E)} is expression-equivalent to: |
| 257 | +\begin{itemize} |
| 258 | +\item |
| 259 | +If \tcode{views::all_t<T>} models \libconcept{constant_range}, |
| 260 | +then \tcode{views::all(E)}. |
| 261 | +\item |
| 262 | +Otherwise, |
| 263 | +if \tcode{U} denotes \tcode{empty_view<X>} |
| 264 | +for some type \tcode{X}, then \tcode{auto(views::empty<const X>)}. |
| 265 | +\begin{addedblock} |
| 266 | +\item |
| 267 | +Otherwise, if \tcode{U} denotes \tcode{optional<X\&>} for some type \tcode{X}, then \tcode{optional<const X\&>(E)}. |
| 268 | +\end{addedblock} |
| 269 | +\item |
| 270 | +Otherwise, |
| 271 | +if \tcode{U} denotes \tcode{span<X, Extent>} |
| 272 | +for some type \tcode{X} and some extent \tcode{Extent}, |
| 273 | +then \tcode{span<const X, Extent>(E)}. |
| 274 | +\item |
| 275 | +Otherwise, |
| 276 | +if \tcode{U} denotes \tcode{ref_view<X>} for some type \tcode{X} and |
| 277 | +\tcode{const X} models \libconcept{constant_range}, |
| 278 | +then \tcode{ref_view(static_cast<const X\&>(E.base()))}. |
| 279 | +\item |
| 280 | +Otherwise, |
| 281 | +if \tcode{E} is an lvalue, |
| 282 | +\tcode{const U} models \libconcept{constant_range}, and |
| 283 | +\tcode{U} does not model \libconcept{view}, |
| 284 | +then \tcode{ref_view(static_cast<const U\&>(E))}. |
| 285 | +\item |
| 286 | +Otherwise, \tcode{as_const_view(E)}. |
| 287 | +\end{itemize} |
| 288 | + |
| 289 | +\rSec2[range.reverse]{Reverse view} |
| 290 | + |
| 291 | +\rSec3[range.reverse.overview]{Overview} |
| 292 | + |
| 293 | +\pnum |
| 294 | +\tcode{reverse_view} takes a bidirectional view and produces |
| 295 | +another view that iterates the same elements in reverse order. |
| 296 | + |
| 297 | +\pnum |
| 298 | +\indexlibrarymember{reverse}{views}% |
| 299 | +The name \tcode{views::reverse} denotes a |
| 300 | +range adaptor object\iref{range.adaptor.object}. |
| 301 | +Given a subexpression \tcode{E}, the expression |
| 302 | +\tcode{views::reverse(E)} is expression-equivalent to: |
| 303 | +\begin{itemize} |
| 304 | +\item |
| 305 | + If the type of \tcode{E} is |
| 306 | + a (possibly cv-qualified) specialization of \tcode{reverse_view}, |
| 307 | + then \tcode{E.base()}. |
| 308 | +\begin{addedblock} |
| 309 | +\item |
| 310 | + Otherwise, if \tcode{E} is specialization of \tcode{optional} and \tcode{E} models \tcode{view}, then \tcode{\placeholdernc{decay-copy}(E)}. |
| 311 | +\end{addedblock} |
| 312 | +\item |
| 313 | + Otherwise, if the type of \tcode{E} is \cv{} \tcode{subrange<reverse_iterator<I>, reverse_iterator<I>, K>} |
| 314 | + for some iterator type \tcode{I} and |
| 315 | + value \tcode{K} of type \tcode{subrange_kind}, |
| 316 | + \begin{itemize} |
| 317 | + \item |
| 318 | + if \tcode{K} is \tcode{subrange_kind::sized}, then |
| 319 | +\tcode{subrange<I, I, K>(E.end().base(), E.begin().base(), E.size())}; |
| 320 | + \item |
| 321 | + otherwise, \tcode{subrange<I, I, K>(E.end().base(), E.begin().base())}. |
| 322 | + \end{itemize} |
| 323 | + However, in either case \tcode{E} is evaluated only once. |
| 324 | +\item |
| 325 | + Otherwise, \tcode{reverse_view\{E\}}. |
| 326 | +\end{itemize} |
| 327 | + |
| 328 | + |
| 329 | +\end{wording} |
| 330 | + |
| 331 | + |
| 332 | +\renewcommand{\bibname}{References} |
| 333 | +\bibliographystyle{abstract} |
| 334 | +\bibliography{wg21,mybiblio} |
| 335 | + |
| 336 | + |
| 337 | +\end{document} |
0 commit comments