From Jason Turner

[range.lazy.split]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmpzozfzlci/{from.md → to.md} +461 -0
tmp/tmpzozfzlci/{from.md → to.md} RENAMED
@@ -0,0 +1,461 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Lazy split view <a id="range.lazy.split">[[range.lazy.split]]</a>
2
+
3
+ #### Overview <a id="range.lazy.split.overview">[[range.lazy.split.overview]]</a>
4
+
5
+ `lazy_split_view` takes a view and a delimiter, and splits the view into
6
+ subranges on the delimiter. The delimiter can be a single element or a
7
+ view of elements.
8
+
9
+ The name `views::lazy_split` denotes a range adaptor object
10
+ [[range.adaptor.object]]. Given subexpressions `E` and `F`, the
11
+ expression `views::lazy_split(E, F)` is expression-equivalent to
12
+ `lazy_split_view(E, F)`.
13
+
14
+ [*Example 1*:
15
+
16
+ ``` cpp
17
+ string str{"the quick brown fox"};
18
+ for (auto word : str | views::lazy_split(' ')) {
19
+ for (char ch : word)
20
+ cout << ch;
21
+ cout << '*';
22
+ }
23
+ // The above prints the*quick*brown*fox*
24
+ ```
25
+
26
+ — *end example*]
27
+
28
+ #### Class template `lazy_split_view` <a id="range.lazy.split.view">[[range.lazy.split.view]]</a>
29
+
30
+ ``` cpp
31
+ namespace std::ranges {
32
+ template<auto> struct require-constant; // exposition only
33
+
34
+ template<class R>
35
+ concept tiny-range = // exposition only
36
+ sized_range<R> &&
37
+ requires { typename require-constant<remove_reference_t<R>::size()>; } &&
38
+ (remove_reference_t<R>::size() <= 1);
39
+
40
+ template<input_range V, forward_range Pattern>
41
+ requires view<V> && view<Pattern> &&
42
+ indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
43
+ (forward_range<V> || tiny-range<Pattern>)
44
+ class lazy_split_view : public view_interface<lazy_split_view<V, Pattern>> {
45
+ private:
46
+ V base_ = V(); // exposition only
47
+ Pattern pattern_ = Pattern(); // exposition only
48
+
49
+ non-propagating-cache<iterator_t<V>> current_; // exposition only, present only
50
+ // if forward_range<V> is false
51
+
52
+ // [range.lazy.split.outer], class template lazy_split_view::outer-iterator
53
+ template<bool> struct outer-iterator; // exposition only
54
+
55
+ // [range.lazy.split.inner], class template lazy_split_view::inner-iterator
56
+ template<bool> struct inner-iterator; // exposition only
57
+
58
+ public:
59
+ lazy_split_view()
60
+ requires default_initializable<V> && default_initializable<Pattern> = default;
61
+ constexpr explicit lazy_split_view(V base, Pattern pattern);
62
+
63
+ template<input_range R>
64
+ requires constructible_from<V, views::all_t<R>> &&
65
+ constructible_from<Pattern, single_view<range_value_t<R>>>
66
+ constexpr explicit lazy_split_view(R&& r, range_value_t<R> e);
67
+
68
+ constexpr V base() const & requires copy_constructible<V> { return base_; }
69
+ constexpr V base() && { return std::move(base_); }
70
+
71
+ constexpr auto begin() {
72
+ if constexpr (forward_range<V>) {
73
+ return outer-iterator<simple-view<V> && simple-view<Pattern>>
74
+ {*this, ranges::begin(base_)};
75
+ } else {
76
+ current_ = ranges::begin(base_);
77
+ return outer-iterator<false>{*this};
78
+ }
79
+ }
80
+
81
+ constexpr auto begin() const requires forward_range<V> && forward_range<const V> {
82
+ return outer-iterator<true>{*this, ranges::begin(base_)};
83
+ }
84
+
85
+ constexpr auto end() requires forward_range<V> && common_range<V> {
86
+ return outer-iterator<simple-view<V> && simple-view<Pattern>>
87
+ {*this, ranges::end(base_)};
88
+ }
89
+
90
+ constexpr auto end() const {
91
+ if constexpr (forward_range<V> && forward_range<const V> && common_range<const V>)
92
+ return outer-iterator<true>{*this, ranges::end(base_)};
93
+ else
94
+ return default_sentinel;
95
+ }
96
+ };
97
+
98
+ template<class R, class P>
99
+ lazy_split_view(R&&, P&&) -> lazy_split_view<views::all_t<R>, views::all_t<P>>;
100
+
101
+ template<input_range R>
102
+ lazy_split_view(R&&, range_value_t<R>)
103
+ -> lazy_split_view<views::all_t<R>, single_view<range_value_t<R>>>;
104
+ }
105
+ ```
106
+
107
+ ``` cpp
108
+ constexpr explicit lazy_split_view(V base, Pattern pattern);
109
+ ```
110
+
111
+ *Effects:* Initializes *base\_* with `std::move(base)`, and *pattern\_*
112
+ with `std::move(pattern)`.
113
+
114
+ ``` cpp
115
+ template<input_range R>
116
+ requires constructible_from<V, views::all_t<R>> &&
117
+ constructible_from<Pattern, single_view<range_value_t<R>>>
118
+ constexpr explicit lazy_split_view(R&& r, range_value_t<R> e);
119
+ ```
120
+
121
+ *Effects:* Initializes *base\_* with `views::all(std::forward<R>(r))`,
122
+ and *pattern\_* with `views::single(std::move(e))`.
123
+
124
+ #### Class template `lazy_split_view::outer-iterator` <a id="range.lazy.split.outer">[[range.lazy.split.outer]]</a>
125
+
126
+ ``` cpp
127
+ namespace std::ranges {
128
+ template<input_range V, forward_range Pattern>
129
+ requires view<V> && view<Pattern> &&
130
+ indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
131
+ (forward_range<V> || tiny-range<Pattern>)
132
+ template<bool Const>
133
+ struct lazy_split_view<V, Pattern>::outer-iterator {
134
+ private:
135
+ using Parent = maybe-const<Const, lazy_split_view>; // exposition only
136
+ using Base = maybe-const<Const, V>; // exposition only
137
+ Parent* parent_ = nullptr; // exposition only
138
+
139
+ iterator_t<Base> current_ = iterator_t<Base>(); // exposition only, present only
140
+ // if V models forward_range
141
+
142
+ bool trailing_empty_ = false; // exposition only
143
+
144
+ public:
145
+ using iterator_concept =
146
+ conditional_t<forward_range<Base>, forward_iterator_tag, input_iterator_tag>;
147
+
148
+ using iterator_category = input_iterator_tag; // present only if Base
149
+ // models forward_range
150
+
151
+ // [range.lazy.split.outer.value], class lazy_split_view::outer-iterator::value_type
152
+ struct value_type;
153
+ using difference_type = range_difference_t<Base>;
154
+
155
+ outer-iterator() = default;
156
+ constexpr explicit outer-iterator(Parent& parent)
157
+ requires (!forward_range<Base>);
158
+ constexpr outer-iterator(Parent& parent, iterator_t<Base> current)
159
+ requires forward_range<Base>;
160
+ constexpr outer-iterator(outer-iterator<!Const> i)
161
+ requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
162
+
163
+ constexpr value_type operator*() const;
164
+
165
+ constexpr outer-iterator& operator++();
166
+ constexpr decltype(auto) operator++(int) {
167
+ if constexpr (forward_range<Base>) {
168
+ auto tmp = *this;
169
+ ++*this;
170
+ return tmp;
171
+ } else
172
+ ++*this;
173
+ }
174
+
175
+ friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y)
176
+ requires forward_range<Base>;
177
+
178
+ friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
179
+ };
180
+ }
181
+ ```
182
+
183
+ Many of the specifications in [[range.lazy.split]] refer to the notional
184
+ member *current* of *`outer-iterator`*. *current* is equivalent to
185
+ *`current_`* if `V` models `forward_range`, and `*parent_->current_`
186
+ otherwise.
187
+
188
+ ``` cpp
189
+ constexpr explicit outer-iterator(Parent& parent)
190
+ requires (!forward_range<Base>);
191
+ ```
192
+
193
+ *Effects:* Initializes *parent\_* with `addressof(parent)`.
194
+
195
+ ``` cpp
196
+ constexpr outer-iterator(Parent& parent, iterator_t<Base> current)
197
+ requires forward_range<Base>;
198
+ ```
199
+
200
+ *Effects:* Initializes *parent\_* with `addressof(parent)` and
201
+ *current\_* with `std::move(current)`.
202
+
203
+ ``` cpp
204
+ constexpr outer-iterator(outer-iterator<!Const> i)
205
+ requires Const && convertible_to<iterator_t<V>, iterator_t<Base>>;
206
+ ```
207
+
208
+ *Effects:* Initializes *parent\_* with `i.`*`parent_`* and *current\_*
209
+ with `std::move(i.`*`current_`*`)`.
210
+
211
+ ``` cpp
212
+ constexpr value_type operator*() const;
213
+ ```
214
+
215
+ *Effects:* Equivalent to: `return value_type{*this};`
216
+
217
+ ``` cpp
218
+ constexpr outer-iterator& operator++();
219
+ ```
220
+
221
+ *Effects:* Equivalent to:
222
+
223
+ ``` cpp
224
+ const auto end = ranges::end(parent_->base_);
225
+ if (current == end) {
226
+ trailing_empty_ = false;
227
+ return *this;
228
+ }
229
+ const auto [pbegin, pend] = subrange{parent_->pattern_};
230
+ if (pbegin == pend) ++current;
231
+ else if constexpr (tiny-range<Pattern>) {
232
+ current = ranges::find(std::move(current), end, *pbegin);
233
+ if (current != end) {
234
+ ++current;
235
+ if (current == end)
236
+ trailing_empty_ = true;
237
+ }
238
+ }
239
+ else {
240
+ do {
241
+ auto [b, p] = ranges::mismatch(current, end, pbegin, pend);
242
+ if (p == pend) {
243
+ current = b;
244
+ if (current == end)
245
+ trailing_empty_ = true;
246
+ break; // The pattern matched; skip it
247
+ }
248
+ } while (++current != end);
249
+ }
250
+ return *this;
251
+ ```
252
+
253
+ ``` cpp
254
+ friend constexpr bool operator==(const outer-iterator& x, const outer-iterator& y)
255
+ requires forward_range<Base>;
256
+ ```
257
+
258
+ *Effects:* Equivalent to:
259
+
260
+ ``` cpp
261
+ return x.current_ == y.current_ && x.trailing_empty_ == y.trailing_empty_;
262
+ ```
263
+
264
+ ``` cpp
265
+ friend constexpr bool operator==(const outer-iterator& x, default_sentinel_t);
266
+ ```
267
+
268
+ *Effects:* Equivalent to:
269
+
270
+ ``` cpp
271
+ return x.current == ranges::end(x.parent_->base_) && !x.trailing_empty_;
272
+ ```
273
+
274
+ #### Class `lazy_split_view::outer-iterator::value_type` <a id="range.lazy.split.outer.value">[[range.lazy.split.outer.value]]</a>
275
+
276
+ ``` cpp
277
+ namespace std::ranges {
278
+ template<input_range V, forward_range Pattern>
279
+ requires view<V> && view<Pattern> &&
280
+ indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
281
+ (forward_range<V> || tiny-range<Pattern>)
282
+ template<bool Const>
283
+ struct lazy_split_view<V, Pattern>::outer-iterator<Const>::value_type
284
+ : view_interface<value_type> {
285
+ private:
286
+ outer-iterator i_ = outer-iterator(); // exposition only
287
+
288
+ public:
289
+ value_type() = default;
290
+ constexpr explicit value_type(outer-iterator i);
291
+
292
+ constexpr inner-iterator<Const> begin() const;
293
+ constexpr default_sentinel_t end() const noexcept;
294
+ };
295
+ }
296
+ ```
297
+
298
+ ``` cpp
299
+ constexpr explicit value_type(outer-iterator i);
300
+ ```
301
+
302
+ *Effects:* Initializes *i\_* with `std::move(i)`.
303
+
304
+ ``` cpp
305
+ constexpr inner-iterator<Const> begin() const;
306
+ ```
307
+
308
+ *Effects:* Equivalent to:
309
+ `return `*`inner-iterator`*`<Const>{`*`i_`*`};`
310
+
311
+ ``` cpp
312
+ constexpr default_sentinel_t end() const noexcept;
313
+ ```
314
+
315
+ *Effects:* Equivalent to: `return default_sentinel;`
316
+
317
+ #### Class template `lazy_split_view::inner-iterator` <a id="range.lazy.split.inner">[[range.lazy.split.inner]]</a>
318
+
319
+ ``` cpp
320
+ namespace std::ranges {
321
+ template<input_range V, forward_range Pattern>
322
+ requires view<V> && view<Pattern> &&
323
+ indirectly_comparable<iterator_t<V>, iterator_t<Pattern>, ranges::equal_to> &&
324
+ (forward_range<V> || tiny-range<Pattern>)
325
+ template<bool Const>
326
+ struct lazy_split_view<V, Pattern>::inner-iterator {
327
+ private:
328
+ using Base = maybe-const<Const, V>; // exposition only
329
+ outer-iterator<Const> i_ = outer-iterator<Const>(); // exposition only
330
+ bool incremented_ = false; // exposition only
331
+
332
+ public:
333
+ using iterator_concept = typename outer-iterator<Const>::iterator_concept;
334
+
335
+ using iterator_category = see belownc; // present only if Base
336
+ // models forward_range
337
+ using value_type = range_value_t<Base>;
338
+ using difference_type = range_difference_t<Base>;
339
+
340
+ inner-iterator() = default;
341
+ constexpr explicit inner-iterator(outer-iterator<Const> i);
342
+
343
+ constexpr const iterator_t<Base>& base() const & noexcept;
344
+ constexpr iterator_t<Base> base() && requires forward_range<V>;
345
+
346
+ constexpr decltype(auto) operator*() const { return *i_.current; }
347
+
348
+ constexpr inner-iterator& operator++();
349
+ constexpr decltype(auto) operator++(int) {
350
+ if constexpr (forward_range<Base>) {
351
+ auto tmp = *this;
352
+ ++*this;
353
+ return tmp;
354
+ } else
355
+ ++*this;
356
+ }
357
+
358
+ friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y)
359
+ requires forward_range<Base>;
360
+
361
+ friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
362
+
363
+ friend constexpr decltype(auto) iter_move(const inner-iterator& i)
364
+ noexcept(noexcept(ranges::iter_move(i.i_.current))) {
365
+ return ranges::iter_move(i.i_.current);
366
+ }
367
+
368
+ friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)
369
+ noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current)))
370
+ requires indirectly_swappable<iterator_t<Base>>;
371
+ };
372
+ }
373
+ ```
374
+
375
+ If *`Base`* does not model `forward_range` there is no member
376
+ `iterator_category`. Otherwise, the *typedef-name* `iterator_category`
377
+ denotes:
378
+
379
+ - `forward_iterator_tag` if
380
+ `iterator_traits<iterator_t<Base>>::iterator_category` models
381
+ `derived_from<forward_iterator_tag>`;
382
+ - otherwise, `iterator_traits<iterator_t<Base>>::iterator_category`.
383
+
384
+ ``` cpp
385
+ constexpr explicit inner-iterator(outer-iterator<Const> i);
386
+ ```
387
+
388
+ *Effects:* Initializes *i\_* with `std::move(i)`.
389
+
390
+ ``` cpp
391
+ constexpr const iterator_t<Base>& base() const & noexcept;
392
+ ```
393
+
394
+ *Effects:* Equivalent to: `return `*`i_`*`.`*`current`*`;`
395
+
396
+ ``` cpp
397
+ constexpr iterator_t<Base> base() && requires forward_range<V>;
398
+ ```
399
+
400
+ *Effects:* Equivalent to: `return std::move(`*`i_`*`.`*`current`*`);`
401
+
402
+ ``` cpp
403
+ constexpr inner-iterator& operator++();
404
+ ```
405
+
406
+ *Effects:* Equivalent to:
407
+
408
+ ``` cpp
409
+ incremented_ = true;
410
+ if constexpr (!forward_range<Base>) {
411
+ if constexpr (Pattern::size() == 0) {
412
+ return *this;
413
+ }
414
+ }
415
+ ++i_.current;
416
+ return *this;
417
+ ```
418
+
419
+ ``` cpp
420
+ friend constexpr bool operator==(const inner-iterator& x, const inner-iterator& y)
421
+ requires forward_range<Base>;
422
+ ```
423
+
424
+ *Effects:* Equivalent to:
425
+ `return x.`*`i_`*`.`*`current`*` == y.`*`i_`*`.`*`current`*`;`
426
+
427
+ ``` cpp
428
+ friend constexpr bool operator==(const inner-iterator& x, default_sentinel_t);
429
+ ```
430
+
431
+ *Effects:* Equivalent to:
432
+
433
+ ``` cpp
434
+ auto [pcur, pend] = subrange{x.i_.parent_->pattern_};
435
+ auto end = ranges::end(x.i_.parent_->base_);
436
+ if constexpr (tiny-range<Pattern>) {
437
+ const auto & cur = x.i_.current;
438
+ if (cur == end) return true;
439
+ if (pcur == pend) return x.incremented_;
440
+ return *cur == *pcur;
441
+ } else {
442
+ auto cur = x.i_.current;
443
+ if (cur == end) return true;
444
+ if (pcur == pend) return x.incremented_;
445
+ do {
446
+ if (*cur != *pcur) return false;
447
+ if (++pcur == pend) return true;
448
+ } while (++cur != end);
449
+ return false;
450
+ }
451
+ ```
452
+
453
+ ``` cpp
454
+ friend constexpr void iter_swap(const inner-iterator& x, const inner-iterator& y)
455
+ noexcept(noexcept(ranges::iter_swap(x.i_.current, y.i_.current)))
456
+ requires indirectly_swappable<iterator_t<Base>>;
457
+ ```
458
+
459
+ *Effects:* Equivalent to
460
+ `ranges::iter_swap(x.`*`i_`*`.`*`current`*`, y.`*`i_`*`.`*`current`*`)`.
461
+