Skip to content

Commit 32fb170

Browse files
committed
Updated README.md for v1.4.0
1 parent c2146bf commit 32fb170

1 file changed

Lines changed: 84 additions & 100 deletions

File tree

README.md

Lines changed: 84 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
C++ range streaming proposal
22
============================
33

4-
Version: 1.0
4+
Version: 1.4.0
55

66

77

@@ -107,36 +107,23 @@ reading or writing sequences to or from streams has a number of issues:
107107
you're getting a container full of junk, and you'll have no idea where
108108
things went wrong.
109109
110-
This proposal suggests the addition of new manipulator-like functions for
111-
streaming ranges to or from streams. Reading a stream into a range is as simple
112-
as:
110+
This proposal suggests the addition of new manipulator-like functions (but
111+
*not* manipulators) for streaming ranges to or from streams.
113112
114-
```C++
115-
// Overwrite each item in r with a value read from the stream, stopping
116-
// immediately when bool(in) is false.
117-
in >> std::stream_range(r);
118-
````
113+
### Output
119114
120-
Writing a range to a stream is just as easy:
115+
Writing the contents of a range `r` to a stream is as simple as:
121116
122117
```C++
123-
// Write each item in r to the stream in order, stopping immediately when
124-
// bool(out) is false.
125118
out << std::stream_range(r);
126119
```
127120

128-
You can even use delimiters - *real* delimiters, which only appear *between*
129-
items - like this:
121+
If you want delimiters between each value written:
130122

131123
```C++
132-
// Write each item in r to the stream in order - writing delimiter between
133-
// each item - stopping immediately when bool(out) is false.
134-
out << std::stream_range(r, delimiter);
124+
out << std::stream_range(r, '\n');
135125
```
136126

137-
Even a C++ newbie, so long as ze is even vaguely familiar with stream I/O, can
138-
figure out what is going on here.
139-
140127
And because this structure is natural for I/O, everything else becomes easier.
141128
Recall the code from N4066:
142129

@@ -150,7 +137,7 @@ std::cout << ")"; // Prints (1, 4, 6) as desired
150137
With range streaming, that becomes:
151138
152139
```C++
153-
std::vector<int> v = {1, 4, 6};
140+
auto v = std::vector<int>{1, 4, 6};
154141
std::cout << '(' << std::stream_range(v, ", ") << ')'; // Prints (1, 4, 6)
155142
```
156143

@@ -163,122 +150,119 @@ std::cout << '(' << std::stream_range({ 1, 4, 6 }, ", ") << ')';
163150
std::cout << '(' << std::stream_range(std::vector<int>{ 1, 4, 6 }, ", ") << ')';
164151
```
165152
166-
The range used can be any type that works as the range in a range-`for`
167-
expression. The delimiter - which only applies to output - can be any type that
168-
has an `operator<<` defined for output streams (the delimiter does not apply to
169-
input streams). In all cases, no copies are made unless necessary (when the
170-
range or the delimiter is passed as an rvalue, it is necessary to keep a copy
171-
constructed by moving from the argument(s)).
172-
173-
In the table below:
174-
175-
* `is` is an object of type `std::basic_istream<CharT, Traits>`
176-
* `os` is an object of type `std::basic_ostream<CharT, Traits>`
177-
* `lr` is a non-`const` lvalue reference to a range
178-
* `cr` is a possibly `const` lvalue reference to a range
179-
* `rr` is a non-`const` rvalue to a range range
180-
* `cd` is a possibly `const` lvalue or a `const` rvalue of a type that has
181-
`operator<<` defined for `std::basic_ostream<CharT, Traits>`.
182-
* `rd` is a non-`const` rvalue of a type that has
183-
`operator<<` defined for `std::basic_ostream<CharT, Traits>`.
184-
185-
| Expression | Expression result | Effects |
186-
| :--------------------------- | :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- |
187-
| `is >> stream_range(lr)` | reference to `is` | Each element in `lr` is overwritten by a value read from `is`. Stops immediately when `bool(is)` is `false`. |
188-
| `is >> stream_range(rr)` | reference to `is` | Each element in `rr` is overwritten by a value read from `is`. Stops immediately when `bool(is)` is `false`. |
189-
| `os << stream_range(cr)` | reference to `os` | Each element in `cr` is written to `os`. `cr` is not copied. Stops immediately when `bool(os)` is `false`. |
190-
| `os << stream_range(rr)` | reference to `os` | `rr` is moved and stored internally, then each element is written to `os`. Stops immediately when `bool(os)` is `false`. |
191-
| `os << stream_range(cr, cd)` | reference to `os` | Each element in `cr` is written to `os`, with `cd` written between each element. `cr` is not copied. Stops immediately when `bool(os)` is `false`. |
192-
| `os << stream_range(cr, rd)` | reference to `os` | Each element in `cr` is written to `os`, with `rd` written between each element. `cr` is not copied. Stops immediately when `bool(os)` is `false`. |
193-
| `os << stream_range(rr, cd)` | reference to `os` | `rr` is moved and stored internally, then each element is written to `os`, with `cd` written between each element. Stops immediately when `bool(os)` is `false`. |
194-
| `os << stream_range(rr, rd)` | reference to `os` | `rr` is moved and stored internally, then each element is written to `os`, with `rd` written between each element. Stops immediately when `bool(os)` is `false`. |
195-
196-
This proposal focuses on ranges supplied as is, rather than the "traditional"
197-
C++ way: as a pair of iterators. The intention is that if you *do* wish to use
198-
a pair of iterators, you can do this (assuming something like N3350 gets
199-
accepted):
153+
Unlike with the copy/stream-iterator model, stream errors are detected and
154+
handled properly. The stream's conversion to `bool` is checked after each write
155+
(attempt), and if it is `false`, the function stops attemping to write and
156+
returns immediately. You can query the number of elements that were written
157+
with the `count()` function:
200158
201159
```C++
202-
os << std::stream_range(std::make_range(begin, end));
203-
os << std::stream_range(std::make_range(begin, end), delimiter);
160+
auto p = std::stream_range(r);
161+
out << r;
162+
std::cout << p.count() << " items were written of " << r.size() << " in the range.";
204163
```
205164

206-
However, for completeness, I have also included the following forms:
165+
Also unlike with the copy/stream-iterator model, formatting is handled correctly.
166+
With the following code:
207167

208168
```C++
209-
os << std::stream_iterator_range(begin, end);
210-
os << std::stream_iterator_range(begin, end, delimiter);
211-
```
212-
213-
Which are equivalent to what is shown above.
169+
std::cout.fill('_');
170+
std::cout.setf(std::ios_base::hex, std::ios_base::basefield);
214171

172+
std::cout << 'x' << std::setw(5) << std::stream_range(r, '|') << 'x';
173+
```
215174

175+
Then the output will be (dependent on the content of `r`):
216176

217-
Installation
218-
------------
177+
```
178+
// r = {} (r is empty)
179+
x_____x
180+
// r = { 25 }
181+
x___19x
182+
// r = { 6, 24, 151 }
183+
x____6|___18|___97x
184+
```
219185

220-
The entire proposal is contained in a single header file. Just make sure it can
221-
be found on the include path, and you can use it.
186+
### Input
222187

223-
For more details, please see the file called “INSTALL”.
188+
Input comes in 4 different forms:
224189

190+
* Overwriting.
191+
* Back inserting.
192+
* Front inserting.
193+
* General inserting.
225194

195+
The latter three mimic the behaviour of the existing `back_insert_iterator`,
196+
`front_insert_iterator`, and `insert_iterator`, respectively.
226197

227-
Possible future directions
228-
--------------------------
198+
The following reads 4 `int` values from `std::cin`, overwriting the contents
199+
of `r`:
229200

230-
`std::stream_range` works for input - for a range with `N` elements, it will
231-
(attempt) to read `N` items from the input stream. That means you must know
232-
in advance how many items there are in the input source. Unfortunately, it
233-
also means that if there is a failure before all `N` elements are read, you
234-
don't know which elements in the range were successfully read.
201+
```C++
202+
auto r = std::array<int, 4>{};
203+
std::cin >> std::overwrite(r);
204+
```
235205
236-
For more practical input situations, the following additional range streaming
237-
functions might be handy:
206+
The following code reads double values from `infile` until `EOF` or a parse
207+
error, and uses `push_back()` to add the values to `r`:
238208
239209
```C++
240-
std::stream_range_back_insert(Range&&)
241-
std::stream_range_front_insert(Range&&)
242-
std::stream_range_insert(Range&&, Iterator)
210+
auto r = std::deque<double>{};
211+
std::cin >> std::back_insert(r);
243212
```
244213

245-
The basic `std::stream_range(Range&&)` as applied to input is essentially:
214+
If you wish to use `push_front()` instead, just replace `back_insert()` with
215+
`front_insert()`:
246216

247217
```C++
248-
std::copy_n(std::istream_iterator<T>{in}, std::size(r), std::begin(r))
218+
auto r = std::deque<double>{};
219+
std::cin >> std::front_insert(r);
249220
```
250221
251-
except that it will stop immediately whenever `bool(in)` is false. By analogy,
252-
these other three functions, in turn, would be:
222+
If you wish to insert into any place in `r`, use `insert()` with an iterator to
223+
the spot to insert before:
253224
254225
```C++
255-
std::copy(std::istream_iterator<T>{in}, std::istream_iterator<T>{}, std::back_inserter(r))
256-
std::copy(std::istream_iterator<T>{in}, std::istream_iterator<T>{}, std::front_inserter(r))
257-
std::copy(std::istream_iterator<T>{in}, std::istream_iterator<T>{}, std::inserter(r, r.begin()))
226+
auto r = std::vector<int>{ 0, 1 };
227+
std::cin >> std::insert(r, std::next(std::begin(r), 1));
258228
```
259229

260-
Another handy extension might be to have these functions also take an
261-
optional size argument, allowing them to read up to that many items, stopping
262-
early if the stream goes into a bad state:
230+
Error checking works, too:
263231

264232
```C++
265-
std::stream_range_back_insert(Range&&, Size)
266-
std::stream_range_front_insert(Range&&, Size)
267-
std::stream_range_insert(Range&&, Iterator, Size)
233+
auto r = std::array<int, 100>{};
234+
auto p = std::overwrite(r);
235+
if (!(std::cin >> p))
236+
std::cerr << "Error: only " << p.count() << " items were read successfully.";
268237
```
269238

270-
These functions would essentially be:
239+
Formatting also works:
271240

272241
```C++
273-
std::copy_n(std::istream_iterator<T>{in}, n, std::back_inserter(r))
274-
std::copy_n(std::istream_iterator<T>{in}, n, std::front_inserter(r))
275-
std::copy_n(std::istream_iterator<T>{in}, n, std::inserter(r, r.begin()))
242+
auto iss = std::istringstream{"abcdef"};
243+
auto r = std::vector<std::string>{};
244+
iss >> std::setw(2) >> std::back_insert(r);
245+
// r is { "ab", "cd", "ef" }
276246
```
277247
278-
except they would stop early if the input stream goes into a bad state.
248+
For more details see the `doc` directory.
249+
250+
251+
252+
Installation
253+
------------
254+
255+
The entire proposal is contained in a single header file. Just make sure it can
256+
be found on the include path, and you can use it.
257+
258+
For more details, please see the file called “INSTALL”.
259+
260+
261+
262+
Possible future directions
263+
--------------------------
279264
280-
These functions may be added in a future version of this library, once some
281-
questions have been addressed.
265+
See `doc/Ideas` for some ideas being considered.
282266
283267
284268

0 commit comments

Comments
 (0)