From Jason Turner

[syncstream]

Diff to HTML by rtfpessoa

Files changed (1) hide show
  1. tmp/tmp57myx5i7/{from.md → to.md} +413 -0
tmp/tmp57myx5i7/{from.md → to.md} RENAMED
@@ -0,0 +1,413 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## Synchronized output streams <a id="syncstream">[[syncstream]]</a>
2
+
3
+ ### Header `<syncstream>` synopsis <a id="syncstream.syn">[[syncstream.syn]]</a>
4
+
5
+ ``` cpp
6
+ #include <ostream> // see [ostream.syn]
7
+
8
+ namespace std {
9
+ template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
10
+ class basic_syncbuf;
11
+
12
+ using syncbuf = basic_syncbuf<char>;
13
+ using wsyncbuf = basic_syncbuf<wchar_t>;
14
+
15
+ template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
16
+ class basic_osyncstream;
17
+
18
+ using osyncstream = basic_osyncstream<char>;
19
+ using wosyncstream = basic_osyncstream<wchar_t>;
20
+ }
21
+ ```
22
+
23
+ The header `<syncstream>` provides a mechanism to synchronize execution
24
+ agents writing to the same stream.
25
+
26
+ ### Class template `basic_syncbuf` <a id="syncstream.syncbuf">[[syncstream.syncbuf]]</a>
27
+
28
+ #### Overview <a id="syncstream.syncbuf.overview">[[syncstream.syncbuf.overview]]</a>
29
+
30
+ ``` cpp
31
+ namespace std {
32
+ template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
33
+ class basic_syncbuf : public basic_streambuf<charT, traits> {
34
+ public:
35
+ using char_type = charT;
36
+ using int_type = typename traits::int_type;
37
+ using pos_type = typename traits::pos_type;
38
+ using off_type = typename traits::off_type;
39
+ using traits_type = traits;
40
+ using allocator_type = Allocator;
41
+
42
+ using streambuf_type = basic_streambuf<charT, traits>;
43
+
44
+ // [syncstream.syncbuf.cons], construction and destruction
45
+ basic_syncbuf()
46
+ : basic_syncbuf(nullptr) {}
47
+ explicit basic_syncbuf(streambuf_type* obuf)
48
+ : basic_syncbuf(obuf, Allocator()) {}
49
+ basic_syncbuf(streambuf_type*, const Allocator&);
50
+ basic_syncbuf(basic_syncbuf&&);
51
+ ~basic_syncbuf();
52
+
53
+ // [syncstream.syncbuf.assign], assignment and swap
54
+ basic_syncbuf& operator=(basic_syncbuf&&);
55
+ void swap(basic_syncbuf&);
56
+
57
+ // [syncstream.syncbuf.members], member functions
58
+ bool emit();
59
+ streambuf_type* get_wrapped() const noexcept;
60
+ allocator_type get_allocator() const noexcept;
61
+ void set_emit_on_sync(bool) noexcept;
62
+
63
+ protected:
64
+ // [syncstream.syncbuf.virtuals], overridden virtual functions
65
+ int sync() override;
66
+
67
+ private:
68
+ streambuf_type* wrapped; // exposition only
69
+ bool emit_on_sync{}; // exposition only
70
+ };
71
+
72
+ // [syncstream.syncbuf.special], specialized algorithms
73
+ template<class charT, class traits, class Allocator>
74
+ void swap(basic_syncbuf<charT, traits, Allocator>&,
75
+ basic_syncbuf<charT, traits, Allocator>&);
76
+ }
77
+ ```
78
+
79
+ Class template `basic_syncbuf` stores character data written to it,
80
+ known as the associated output, into internal buffers allocated using
81
+ the object’s allocator. The associated output is transferred to the
82
+ wrapped stream buffer object `*wrapped` when `emit()` is called or when
83
+ the `basic_syncbuf` object is destroyed. Such transfers are atomic with
84
+ respect to transfers by other `basic_syncbuf` objects with the same
85
+ wrapped stream buffer object.
86
+
87
+ #### Construction and destruction <a id="syncstream.syncbuf.cons">[[syncstream.syncbuf.cons]]</a>
88
+
89
+ ``` cpp
90
+ basic_syncbuf(streambuf_type* obuf, const Allocator& allocator);
91
+ ```
92
+
93
+ *Effects:* Sets `wrapped` to `obuf`.
94
+
95
+ *Remarks:* A copy of `allocator` is used to allocate memory for internal
96
+ buffers holding the associated output.
97
+
98
+ *Throws:* Nothing unless an exception is thrown by the construction of a
99
+ mutex or by memory allocation.
100
+
101
+ *Ensures:* `get_wrapped() == obuf` and `get_allocator() == allocator`
102
+ are `true`.
103
+
104
+ ``` cpp
105
+ basic_syncbuf(basic_syncbuf&& other);
106
+ ```
107
+
108
+ *Ensures:* The value returned by `this->get_wrapped()` is the value
109
+ returned by `other.get_wrapped()` prior to calling this constructor.
110
+ Output stored in `other` prior to calling this constructor will be
111
+ stored in `*this` afterwards.
112
+ `other.rdbuf()->pbase() == other.rdbuf()->pptr()` and
113
+ `other.get_wrapped() == nullptr` are `true`.
114
+
115
+ *Remarks:* This constructor disassociates `other` from its wrapped
116
+ stream buffer, ensuring destruction of `other` produces no output.
117
+
118
+ ``` cpp
119
+ ~basic_syncbuf();
120
+ ```
121
+
122
+ *Effects:* Calls `emit()`.
123
+
124
+ *Throws:* Nothing. If an exception is thrown from `emit()`, the
125
+ destructor catches and ignores that exception.
126
+
127
+ #### Assignment and swap <a id="syncstream.syncbuf.assign">[[syncstream.syncbuf.assign]]</a>
128
+
129
+ ``` cpp
130
+ basic_syncbuf& operator=(basic_syncbuf&& rhs) noexcept;
131
+ ```
132
+
133
+ *Effects:* Calls `emit()` then move assigns from `rhs`. After the move
134
+ assignment `*this` has the observable state it would have had if it had
135
+ been move constructed from `rhs` [[syncstream.syncbuf.cons]].
136
+
137
+ *Returns:* `*this`.
138
+
139
+ *Ensures:*
140
+
141
+ - `rhs.get_wrapped() == nullptr` is `true`.
142
+ - `this->get_allocator() == rhs.get_allocator()` is `true` when
143
+ ``` cpp
144
+ allocator_traits<Allocator>::propagate_on_container_move_assignment::value
145
+ ```
146
+
147
+ is `true`; otherwise, the allocator is unchanged.
148
+
149
+ *Remarks:* This assignment operator disassociates `rhs` from its wrapped
150
+ stream buffer, ensuring destruction of `rhs` produces no output.
151
+
152
+ ``` cpp
153
+ void swap(basic_syncbuf& other) noexcept;
154
+ ```
155
+
156
+ *Preconditions:* Either
157
+ `allocator_traits<Allocator>::propagate_on_container_swap::value` is
158
+ `true` or `this->get_allocator() == other.get_allocator()` is `true`.
159
+
160
+ *Effects:* Exchanges the state of `*this` and `other`.
161
+
162
+ #### Member functions <a id="syncstream.syncbuf.members">[[syncstream.syncbuf.members]]</a>
163
+
164
+ ``` cpp
165
+ bool emit();
166
+ ```
167
+
168
+ *Effects:* Atomically transfers the associated output of `*this` to the
169
+ stream buffer `*wrapped`, so that it appears in the output stream as a
170
+ contiguous sequence of characters. `wrapped->pubsync()` is called if and
171
+ only if a call was made to `sync()` since the most recent call to
172
+ `emit()`, if any.
173
+
174
+ *Returns:* `true` if all of the following conditions hold; otherwise
175
+ `false`:
176
+
177
+ - `wrapped == nullptr` is `false`.
178
+ - All of the characters in the associated output were successfully
179
+ transferred.
180
+ - The call to `wrapped->pubsync()` (if any) succeeded.
181
+
182
+ *Ensures:* On success, the associated output is empty.
183
+
184
+ *Synchronization:* All `emit()` calls transferring characters to the
185
+ same stream buffer object appear to execute in a total order consistent
186
+ with the “happens before” relation [[intro.races]], where each `emit()`
187
+ call synchronizes with subsequent `emit()` calls in that total order.
188
+
189
+ *Remarks:* May call member functions of `wrapped` while holding a lock
190
+ uniquely associated with `wrapped`.
191
+
192
+ ``` cpp
193
+ streambuf_type* get_wrapped() const noexcept;
194
+ ```
195
+
196
+ *Returns:* `wrapped`.
197
+
198
+ ``` cpp
199
+ allocator_type get_allocator() const noexcept;
200
+ ```
201
+
202
+ *Returns:* A copy of the allocator that was set in the constructor or
203
+ assignment operator.
204
+
205
+ ``` cpp
206
+ void set_emit_on_sync(bool b) noexcept;
207
+ ```
208
+
209
+ *Effects:* `emit_on_sync = b`.
210
+
211
+ #### Overridden virtual functions <a id="syncstream.syncbuf.virtuals">[[syncstream.syncbuf.virtuals]]</a>
212
+
213
+ ``` cpp
214
+ int sync() override;
215
+ ```
216
+
217
+ *Effects:* Records that the wrapped stream buffer is to be flushed.
218
+ Then, if `emit_on_sync` is `true`, calls `emit()`.
219
+
220
+ [*Note 1*: If `emit_on_sync` is `false`, the actual flush is delayed
221
+ until a call to `emit()`. — *end note*]
222
+
223
+ *Returns:* If `emit()` was called and returned `false`, returns `-1`;
224
+ otherwise `0`.
225
+
226
+ #### Specialized algorithms <a id="syncstream.syncbuf.special">[[syncstream.syncbuf.special]]</a>
227
+
228
+ ``` cpp
229
+ template<class charT, class traits, class Allocator>
230
+ void swap(basic_syncbuf<charT, traits, Allocator>& a,
231
+ basic_syncbuf<charT, traits, Allocator>& b) noexcept;
232
+ ```
233
+
234
+ *Effects:* Equivalent to `a.swap(b)`.
235
+
236
+ ### Class template `basic_osyncstream` <a id="syncstream.osyncstream">[[syncstream.osyncstream]]</a>
237
+
238
+ #### Overview <a id="syncstream.osyncstream.overview">[[syncstream.osyncstream.overview]]</a>
239
+
240
+ ``` cpp
241
+ namespace std {
242
+ template<class charT, class traits = char_traits<charT>, class Allocator = allocator<charT>>
243
+ class basic_osyncstream : public basic_ostream<charT, traits> {
244
+ public:
245
+ using char_type = charT;
246
+ using int_type = typename traits::int_type;
247
+ using pos_type = typename traits::pos_type;
248
+ using off_type = typename traits::off_type;
249
+ using traits_type = traits;
250
+
251
+ using allocator_type = Allocator;
252
+ using streambuf_type = basic_streambuf<charT, traits>;
253
+ using syncbuf_type = basic_syncbuf<charT, traits, Allocator>;
254
+
255
+ // [syncstream.osyncstream.cons], construction and destruction
256
+ basic_osyncstream(streambuf_type*, const Allocator&);
257
+ explicit basic_osyncstream(streambuf_type* obuf)
258
+ : basic_osyncstream(obuf, Allocator()) {}
259
+ basic_osyncstream(basic_ostream<charT, traits>& os, const Allocator& allocator)
260
+ : basic_osyncstream(os.rdbuf(), allocator) {}
261
+ explicit basic_osyncstream(basic_ostream<charT, traits>& os)
262
+ : basic_osyncstream(os, Allocator()) {}
263
+ basic_osyncstream(basic_osyncstream&&) noexcept;
264
+ ~basic_osyncstream();
265
+
266
+ // assignment
267
+ basic_osyncstream& operator=(basic_osyncstream&&) noexcept;
268
+
269
+ // [syncstream.osyncstream.members], member functions
270
+ void emit();
271
+ streambuf_type* get_wrapped() const noexcept;
272
+ syncbuf_type* rdbuf() const noexcept { return const_cast<syncbuf_type*>(addressof(sb)); }
273
+
274
+ private:
275
+ syncbuf_type sb; // exposition only
276
+ };
277
+ }
278
+ ```
279
+
280
+ `Allocator` shall meet the *Cpp17Allocator* requirements (
281
+ [[cpp17.allocator]]).
282
+
283
+ [*Example 1*:
284
+
285
+ A named variable can be used within a block statement for streaming.
286
+
287
+ ``` cpp
288
+ {
289
+ osyncstream bout(cout);
290
+ bout << "Hello, ";
291
+ bout << "World!";
292
+ bout << endl; // flush is noted
293
+ bout << "and more!\n";
294
+ } // characters are transferred and cout is flushed
295
+ ```
296
+
297
+ — *end example*]
298
+
299
+ [*Example 2*:
300
+
301
+ A temporary object can be used for streaming within a single statement.
302
+
303
+ ``` cpp
304
+ osyncstream(cout) << "Hello, " << "World!" << '\n';
305
+ ```
306
+
307
+ In this example, `cout` is not flushed.
308
+
309
+ — *end example*]
310
+
311
+ #### Construction and destruction <a id="syncstream.osyncstream.cons">[[syncstream.osyncstream.cons]]</a>
312
+
313
+ ``` cpp
314
+ basic_osyncstream(streambuf_type* buf, const Allocator& allocator);
315
+ ```
316
+
317
+ *Effects:* Initializes `sb` from `buf` and `allocator`. Initializes the
318
+ base class with `basic_ostream<charT, traits>(addressof(sb))`.
319
+
320
+ [*Note 1*: The member functions of the provided stream buffer might be
321
+ called from `emit()` while a lock is held. Care should be taken to
322
+ ensure that this does not result in deadlock. — *end note*]
323
+
324
+ *Ensures:* `get_wrapped() == buf` is `true`.
325
+
326
+ ``` cpp
327
+ basic_osyncstream(basic_osyncstream&& other) noexcept;
328
+ ```
329
+
330
+ *Effects:* Move constructs the base class and `sb` from the
331
+ corresponding subobjects of `other`, and calls
332
+ `basic_ostream<charT, traits>::set_rdbuf(addressof(sb))`.
333
+
334
+ *Ensures:* The value returned by `get_wrapped()` is the value returned
335
+ by `os.get_wrapped()` prior to calling this constructor.
336
+ `nullptr == other.get_wrapped()` is `true`.
337
+
338
+ #### Member functions <a id="syncstream.osyncstream.members">[[syncstream.osyncstream.members]]</a>
339
+
340
+ ``` cpp
341
+ void emit();
342
+ ```
343
+
344
+ *Effects:* Calls `sb.emit()`. If that call returns `false`, calls
345
+ `setstate(ios_base::badbit)`.
346
+
347
+ [*Example 1*:
348
+
349
+ A flush on a `basic_osyncstream` does not flush immediately:
350
+
351
+ ``` cpp
352
+ {
353
+ osyncstream bout(cout);
354
+ bout << "Hello," << '\n'; // no flush
355
+ bout.emit(); // characters transferred; cout not flushed
356
+ bout << "World!" << endl; // flush noted; cout not flushed
357
+ bout.emit(); // characters transferred; cout flushed
358
+ bout << "Greetings." << '\n'; // no flush
359
+ } // characters transferred; cout not flushed
360
+ ```
361
+
362
+ — *end example*]
363
+
364
+ [*Example 2*:
365
+
366
+ The function `emit()` can be used to handle exceptions from operations
367
+ on the underlying stream.
368
+
369
+ ``` cpp
370
+ {
371
+ osyncstream bout(cout);
372
+ bout << "Hello, " << "World!" << '\n';
373
+ try {
374
+ bout.emit();
375
+ } catch (...) {
376
+ // handle exception
377
+ }
378
+ }
379
+ ```
380
+
381
+ — *end example*]
382
+
383
+ ``` cpp
384
+ streambuf_type* get_wrapped() const noexcept;
385
+ ```
386
+
387
+ *Returns:* `sb.get_wrapped()`.
388
+
389
+ [*Example 3*:
390
+
391
+ Obtaining the wrapped stream buffer with `get_wrapped()` allows wrapping
392
+ it again with an `osyncstream`. For example,
393
+
394
+ ``` cpp
395
+ {
396
+ osyncstream bout1(cout);
397
+ bout1 << "Hello, ";
398
+ {
399
+ osyncstream(bout1.get_wrapped()) << "Goodbye, " << "Planet!" << '\n';
400
+ }
401
+ bout1 << "World!" << '\n';
402
+ }
403
+ ```
404
+
405
+ produces the *uninterleaved* output
406
+
407
+ ``` text
408
+ Goodbye, Planet!
409
+ Hello, World!
410
+ ```
411
+
412
+ — *end example*]
413
+