From Jason Turner

[range.split]

Diff to HTML by rtfpessoa

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