<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<!-- saved from url=(0077)file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#PSL -->
<html><head><meta http-equiv="Content-Type" content="text/html; charset=windows-1252">



<style type="text/css">

body {
  color: #000000;
  background-color: #FFFFFF;
}

del {
  text-decoration: line-through;
  color: #8B0040;
}
ins {
  text-decoration: underline;
  color: #005100;
}

dl.tldr {
  background-color: #F9F9F9;
  border: 1px solid #D1D1D1;
}
dt.question {
  color: #CC0000;
  font-weight: 900;
}
dd.answer {
  color: #008800;
}

p.example {
  margin: 2em;
}
pre.example {
  margin: 2em;
}
div.example {
  margin: 2em;
}

code.extract {
  background-color: #F5F6A2;
}
pre.extract {
  margin: 2em;
  background-color: #F5F6A2;
  border: 1px solid #E1E28E;
}

p.function {
}

p.attribute {
  text-indent: 3em;
}

blockquote.std {
  color: #000000;
  background-color: #F1F1F1;
  border: 1px solid #D1D1D1;
  padding: 0.5em;
}

blockquote.stddel {
  text-decoration: line-through;
  color: #000000;
  background-color: #FFEBFF;
  border: 1px solid #ECD7EC;
  padding: 0.5em;
}

blockquote.stdins {
  text-decoration: underline;
  color: #000000;
  background-color: #C8FFC8;
  border: 1px solid #B3EBB3;
  padding: 0.5em;
}

table {
  border: 1px solid black;
  border-spacing: 0px;
  margin-left: auto;
  margin-right: auto;
}
th {
  text-align: left;
  vertical-align: top;
  padding: 0.2em;
  border: none;
}
td {
  text-align: left;
  vertical-align: top;
  padding: 0.2em;
  border: none;
}

</style>

<title>DRAFT C++ Synchronized Buffered Ostream</title>
</head>
<body>
<h1>DRAFT C++ Synchronized Buffered Ostream</h1>

<p>
ISO/IEC JTC1 SC22 WG21 d0053r4 - 2017-03-02
</p>

<p>
Lawrence Crowl, Lawrence@Crowl.org<br>
Peter Sommerlad, Peter.Sommerlad@hsr.ch<br>
Nicolai Josuttis<br>
Pablo Halpern
</p>

<p>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Introduction">Introduction</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Solution">Solution</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Design">Design</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Feature">Feature Test</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Wording">Wording</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#contents">Headers [headers]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#input.output.general">General [input.output.general]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#iostream.forward">Forward declarations [iostream.forward]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream">Synchronized output stream [syncstream]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.overview">Overview [syncstream.overview]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.syncbuf">Class template <code>basic_syncbuf</code> [syncstream.syncbuf]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.sycnbuf.ctor"><code>basic_syncbuf</code> constructors [syncstream.syncbuf.ctor]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.sycnbuf.dtor"><code>basic_syncbuf</code> destructor [syncstream.syncbuf.dtor]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.sycnbuf.assign"><code>basic_syncbuf</code> assign and swap [syncstream.syncbuf.assign]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.syncbuf.mfun"><code>basic_syncbuf</code> member functions [syncstream.syncbuf.mfun]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.syncbuf.virtuals"><code>basic_syncbuf</code> overridden virtual functions [syncstream.syncbuf.virtuals]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.osyncstream">Class template <code>basic_osyncstream</code> [syncstream.osyncstream]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#synstream.osyncstream.ctor"><code>osyncstream</code> Constructor [syncstream.osyncstream.ctor]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#synstream.osyncstream.dtor"><code>osyncstream</code> Destructor [synstream.osyncstream.dtor]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#synstream.osyncstream.assign"><code>osyncstream</code> Assignment [synstream.osyncstream.assign]</a><br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#syncstream.osyncstream.mfun"><code>osyncstream</code> Member Functions [syncstream.osyncstream.mfun]</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#implementation">Implementation</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#Revisions">Revisions</a><br>
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#References">References</a><br>
</p>


<h2><a name="Introduction">Introduction</a></h2>

<p>
At present,
some stream output operations guarantee that they will not produce race conditions,
but do not guarantee that the effect will be sensible.
Some form of external synchronization is required.
Unfortunately, without a standard mechanism for synchronizing,
independently developed software will be unable to synchronize.
</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html">
N3535 C++ Stream Mutexes</a>
proposed a standard mechanism for finding and sharing a mutex on streams.
At the Spring 2013 standards meeting,
the Concurrency Study Group requested a change
away from a full mutex definition
to a definition that also enabled buffering.
</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html">
N3678 C++ Stream Guards</a>
proposed a standard mechanism for batching operations on a stream.
That batching may be implemented as mutexes, as buffering,
or some combination of both.
It was the response to the Concurrency Study Group.
A draft of that paper was reviewed in the Library Working Group,
who found too many open issues on what was reasonably exposed
to the 'buffering' part.
</p>

<p>
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3665.html">
N3665 Uninterleaved Sring Output Streaming</a>
proposed making streaming of strings of length less than <code>BUFSIZ</code>
appear uninterleaved in the output.
It was a "minimal" functionality change to the existing standard
to address the problem.
The full Committee chose not to adopt that minimal solution.
</p>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3750.html">N3750
C++ Ostream Buffers</a> proposed an explicit buffering,
at the direction of the general consensus
in the July 2013 meeting of the Concurrency Study Group.
In November 2014 a further updated version
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4187.html">N4187</a>
was discussed in Library Evolution in Urbana
and it was consensus to work with a library expert
to get the naming and wording better suited to LWG expectations.
Nico Josuttis volunteered to help the original authors.
More information on the discussion is available at
<a href="http://wiki.edg.com/twiki/bin/view/Wg21urbana-champaign/N4187">LEWG
wiki</a>
and the corresponding
<a href="https://issues.isocpp.org/show_bug.cgi?id=20">LEWG
bug tracker entry (20)</a>.
This paper address issues raised with
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4187.html">N4187</a>.
This paper has a change of title to reflect a change in class name,
but contains the same fundamental approach.
</p>


<h2><a name="Solution">Solution</a></h2>

<p>
We propose a <code>basic_osyncstream</code>,
that buffers output operations for a wrapped stream.
The <code>basic_osyncstream</code>
will atomically transfer the contents
of an internal stream buffer
to a <code>basic_ostream</code>'s stream buffer
on destruction of the <code>basic_osyncstream</code>.
</p>

<p>
The transfer on destruction
simplifies the code and
ensures at least some output in the presence of an exception.
</p>

<p>
The intent is that the <code>basic_osyncstream</code>
is an automatic-duration variable
with a relatively small scope
which constructs the text to appear uninterleaved.
For example,
</p>
<pre class="example"><code>{
  osyncstream bout(cout);
  bout &lt;&lt; "Hello, " &lt;&lt; "World!" &lt;&lt; '\n';
}</code></pre>


<h2><a name="Design">Design</a></h2>

<p>
Here we list a set of objection to our proposal
in the form of questions.
We then give our reasons why other potential solutions
do not work as well as our proposed solution.
</p>

<dl class="tldr">

<dt class="question">
Why can I not just use <code>cout</code>?
It should be thread-safe.
</dt>
<dd class="answer"><p>
You will nott get data races for <code>cout</code>,
but that is not true for most other streams.
In addition there is no guarantee that
output from different threads appears in any sensible order.
Coherent output order is the main reason for this proposal.
</p></dd>

<dt class="question">
Why must osyncstream be an <code>ostream</code>?
Could a simple proxy wrapper work?
</dt>
<dd class="answer"><p>
To support all existing and user-defined output operators,
<code>osyncstream</code> must be an <code>ostream</code> subclass.
</p></dd>

<dt class="question">
Can you make a flush of the <code>osyncstream</code>
mean transfer the characters and flush the underlying stream?
</dt>
<dd class="answer"><p>
No, because the point of the <code>osyncstream</code>
is to collect text into an atomic unit.
Flushes are often emitted in calls where the body is not visible,
and hence unintentionally break up the text.
Furthermore, there may be more than one flush
within the lifetime of an <code>osyncstream</code>,
which would impose a performance loss
when an atomic unit of text needs only one flush.
The design decision is only to flush the underlying stream,
if the osyncstream was flushed,
and only once per atomic transfer of the character sequence.
</p></dd>

<dt class="question">
Can you flush just transfer the characters and not flush the underlying stream?
</dt>
<dd class="answer"><p>
The flush intends an effect on visible to the user.
So, we should preserve at least one flush.
The flush may not be visible to the code around the <code>osyncstream</code>,
and so its programmer cannot do a manual flush, because
attempting to flush the underlying stream that is shared among 
threads will introduce a data race.
</p></dd>

<dt class="question">
Why do you specify basic_synbuf? LWG and LEWG thought you wouldn't need it.</dt>
<dd class="answer"><p>
Users use the streambuf interface. 
Without access to the basic_syncbuf they would not be able call emit() on the underlying 
streambuf responsible the synchronization. Ask Pablo Halpern if you need more to be convinced.
</p></dd>

<dt class="question">
Where will the required lock/mutex be put? Will it be in every streambuf object changing the ABI?</dt>
<dd class="answer"><p>
That is one of the reasons, why this must be put into the standard library. 
It is possible to implement with a global map from streambuf* to mutexes as the example code does,
however, existing standard library implementations might have already a space for the mutexes
(not breaking their ABI), 
because cout/cerr seem to require one and those might be the most important ones to wrap.
</p></dd>

</dl>

<p>
While it has been pointed out that the implementation should actually reside in the used stream
buffer object, we believe the specification should hide that effect, because such a 
stream buffer is not intended to be ever be used standalone. Therefore, the specification
here only provides the basic_osyncstream class template and not any details on the 
underlying stream buffer implementing the mechanics. We have an implementation, where the 
basic_osyncstream is more or less just a shell to the real meat in the stream buffer
but that stream buffer is not meant to be exchanged or shared or anything.
</p>

<p>
We follow typical stream conventions
of <code>basic_</code> prefixes and typedefs.
</p>

<p>
The constructor for <code>osyncstream</code>
takes a non-const reference
to a <code>basic_ostream</code> obtaining its stream buffer
or a <code>basic_streambuf</code>.
This stream buffer indicates that
the destruction of the osyncstream
may write to the stream buffer obtained with the constructor argument.
</p>

<p>
The wording below
permits implementation of <code>basic_osyncstream</code>
with either a <code>stream_mutex</code>
from
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html">
N3535</a>
or with implementations suitable for
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3665.html">
N3665</a>,
e.g. with Posix file locks
<a href="file:///Users/sop/Documents/C++WG21/SC22WG21_Papers/drafting/p0053r4.html#PSL">[PSL]</a>
</p>

<h3><a name="Feature">Feature Test</a></h3>

<p>
No header called <code>&lt;syncstream&gt;</code> exists;
testing for this header's existence is thus sufficient
for testing existence of the feature.
</p>

<h2><a name="Wording">Wording</a></h2>

<p>
This wording is relative to the current C++(17) working draft, but doesn't use section numbers.
This allows its integration into the Concurrency TS 2 accordingly.
</p>

<h3><a name="contents">Headers [headers]</a></h3>
<p>Add a new entry to table  C++ library headers :

</p><blockquote class="stdins">
<table>
<tbody><tr>
<td>&lt;syncstream&gt;</td>
</tr>
</tbody></table>
</blockquote>


<h3><a name="input.output.general">General [input.output.general]</a></h3>

<p>
Add a new row to table  Input/output library summary.
</p>

<blockquote class="stdins">
<table>
<tbody><tr>
<td>xx.12</td>
<td>Synchronized output streams</td>
<td>&lt;syncstream&gt;</td>
</tr>
</tbody></table>
</blockquote>

<h3><a name="iostream.forward">Forward declarations [iostream.forward]</a></h3>

<p>
Add the following forward declarations to the synopsis of &lt;iosfwd&gt;
in the <code>namespace std</code>.
</p>

<blockquote class="stdins">
<pre><code>
template &lt;class charT,
          class traits = char_traits&lt;charT&gt;,
          class Allocator = allocator&lt;charT&gt;&gt;
  class basic_syncbuf;
using syncbuf  = basic_syncbuf&lt;char&gt;;
using wsyncbuf = basic_syncbuf&lt;wchar_t&gt;;

template &lt;class charT,
          class traits = char_traits&lt;charT&gt;,
          class Allocator = allocator&lt;charT&gt; &gt;
  class basic_osyncstream;
typedef basic_osyncstream&lt;char&gt; osyncstream;
typedef basic_osyncstream&lt;wchar_t&gt; wosyncstream;
</code></pre>
</blockquote>


<h3><a name="syncstream">Synchronized output stream [syncstream]</a></h3>

<p>
Add a new section with the following subsections.
</p>


<h4><a name="syncstream.overview">Overview [syncstream.overview]</a></h4>

<blockquote class="stdins">
<p>
The header <code>&lt;syncstream&gt;</code>
provides a mechanism to synchronize execution agents writing to the same stream.
It defines a class template <code>basic_osyncstream</code>
to buffer output and
<!--atomically transfer the buffered content into a <code>basic_ostream</code> object.-->
transfer the buffered content into an object of type
<code>basic_streambuf&lt;charT,traits&gt;</code> atomically 
with respect to such transfers by other 
<code>basic_osyncstream&lt;charT,traits,Allocator&gt;</code> objects referring 
to the same <code>basic_streambuf&lt;charT,traits&gt;</code> object.
The transfer occurs when <code>emit()</code> is called
and when the <code>basic_osyncstream&lt;chart,traits,Allocator&gt;</code> 
object is destroyed.
</p>
</blockquote>

<p>
Add a synopsis for header <code>&lt;syncstream&gt;</code>.
</p>

<blockquote class="stdins">
<pre><code>
template &lt;class charT,
          class traits = char_traits&lt;charT&gt;,
          class Allocator = allocator&lt;charT&gt;&gt;
  class basic_syncbuf;
template &lt;class charT,
          class traits,
          class Allocator&gt;
  class basic_osyncstream;
</code></pre>
</blockquote>

<h4><a name="syncstream.syncbuf">Class template <code>basic_syncbuf</code> [syncstream.syncbuf]</a></h4>

<blockquote class="stdins">
<pre><code>template &lt;class charT,
          class traits = char_traits&lt;charT&gt;,
          class Allocator = allocator&lt;charT&gt;&gt;
class basic_syncbuf
  : public std::basic_streambuf&lt;charT, traits, Allocator&gt; {

public:
  using char_type      = charT;
  using int_type       = typename traits::int_type;
  using pos_type       = typename traits::pos_type;
  using off_type       = typename traits::off_type;
  using traits_type    = traits;
  using allocator_type = Allocator;

  using streambuf_type = basic_streambuf&lt;charT,traits&gt;;

  explicit
  basic_syncbuf(streambuf_type* obuf = nullptr)
  : basic_syncbuf(obuf,Allocator{});
  basic_syncbuf(streambuf_type* obuf,
                Allocator const &amp;allocator);
  basic_syncbuf(basic_syncbuf&amp;&amp; other);
  ~basic_syncbuf();

  basic_syncbuf&amp; operator=(basic_syncbuf&amp;&amp; rhs);
  void swap(basic_syncbuf &amp;other);

  bool emit();
  streambuf_type* get_wrapped()   const noexcept;
  allocator_type  get_allocator() const noexcept;

protected:
  int sync() override;

private:
  streambuf_type *wrapped;  // <em>exposition only</em>
};

template &lt;class charT, class traits, class Allocator&gt;
inline void swap(basic_syncbuf&lt;charT,traits,Allocator&gt;&amp; a,
                 basic_syncbuf&lt;charT,traits,Allocator&gt;&amp; b);
</code></pre>
</blockquote>
<!-- removed from above:
  int_type overflow(int_type c = traits::eof()) override;
-->
<h4><a name="syncstream.sycnbuf.ctor"><code>basic_syncbuf</code> constructors [syncstream.syncbuf.ctor]</a></h4>

<blockquote class="stdins">
<dl>
<dt>
<code>explicit
basic_syncbuf(streambuf_type* obuf = nullptr,
              Allocator const &amp;allocator = Allocator());</code>
</dt>
<dd>

<p><i>Effects:</i>
Constructs the <code>basic_syncbuf</code> object and
sets <code>wrapped</code> to <code>obuf</code>
which will be the final destination of characters inserted into the stream.
</p>

<p><i>Remarks:</i>
If <code>obuf == nullptr</code>, output operations on 
<code>*this</code> will fail.
A copy of <code>allocator</code> is used to allocate memory 
for internal buffers.
</p>

<p>
<i>Throws:</i>
Nothing unless constructing a mutex or allocating memory throws.
</p>

<p>
[<i>Note:</i> Subsequent calls to <code>emit()</code> might result in
member functions being called on the user-provided stream buffer 
while a lock is held.
<i>end note</i>]
</p>

<p><i>Postconditions:</i>
<code>get_wrapped() == obuf &amp;&amp; get_allocator() == allocator.</code>.
</p>
</dd>

<dt>
<code>basic_syncbuf(basic_syncbuf&amp;&amp; other);</code>
</dt>
<dd>

<p><i>Effects:</i> If <code>other.get_wrapped() == nullptr</code>, equivalent
to <code>basic_syncbuf(nullptr, other.get_allocator())</code>
otherwise the state necessary to perform <code>other.emit()</code> is moved
to <code>*this</code>.
</p>

<p><i>Postconditions:</i>
The value returned by <code>this-&gt;get_wrapped()</code> is the value 
returned by <code>other.get_wrapped()</code> prior to calling this constructor. 
Output stored in <code>other</code> prior to calling this constructor
will be stored in <code>*this</code> afterwards. 
<code>other.rdbuf()-&gt;pbase() == other.rdbuf()-&gt;pptr()</code>
and <code>other.get_wrapped() == nullptr</code>
</p>

<p>
[<i>Note:</i>
This constructor disassociates <code>other</code> from its wrapped stream buffer 
ensuring destruction of <code>other</code> produces no output.
<i>end note</i>]
</p>
</dd>
</dl>
</blockquote>

<h4><a name="syncstream.sycnbuf.dtor"><code>basic_syncbuf</code> destructor [syncstream.syncbuf.dtor]</a></h4>

<blockquote class="stdins">

<dl>
<dt>
<code>~basic_syncbuf();</code>
</dt>
<dd>

<p><i>Effects:</i> Calls <code>this-&gt;emit()</code>.
</p>
    
<p><i>Throws:</i> Nothing. If an exception is thrown while writing to the
wrapped buffer, that exception is caught and ignored.
</p>
</dd>
</dl>
</blockquote>

<h4><a name="syncstream.sycnbuf.assign"><code>basic_syncbuf</code> assign and swap [syncstream.syncbuf.assign]</a></h4>

<blockquote class="stdins">
<dl>
<dt>
<code>basic_syncbuf&amp; operator=(basic_syncbuf&amp;&amp; rhs);</code>
</dt>
<dd>

<p><i>Effects:</i>
Calls <code>this-&gt;emit()</code>. If <code>rhs.get_wrapped() != nullptr</code>,
the state necessary to perform <code>rhs.emit()</code> is moved
to <code>*this</code>.
</p>  

<p><i>Returns:</i> <code>*this</code>.</p>

<p><i>Postconditions:</i>
<code>other.get_wrapped() == nullptr.</code> If
<code>allocator_traits&lt;Allocator&gt;::propagate_on_container_move_assignment::value == true</code>,
then <code>this-&gt;get_allocator() == other.get_allocator()</code>;
otherwise the allocator is unchanged.
</p>

<p>
[<i>Note:</i>
This assignment operator disassociates <code>other</code> from its wrapped stream
buffer ensuring destruction of <code>other</code> produces no output.
<i>end note</i>]
</p>
</dd>

<dt>
<code>void swap(basic_syncbuf&amp; other);</code>
</dt>
<dd>

<p><i>Preconditions:</i>
<code>this-&gt;get_allocator() == other.get_allocator()</code>.
</p>

<p><i>Effects:</i> Exchanges the state of <code>*this</code> and
<code>other</code>.
</p>
</dd>

<dt>
<code>template &lt;class charT, class traits, class Allocator&gt;
&nbsp;&nbsp;void swap(basic_syncbuf&lt;charT,traits,Allocator&gt;&amp; a,
                      basic_syncbuf&lt;charT,traits,Allocator&gt;&amp; b);
</code>
</dt>
<dd>
<p><i>Effects:</i> As if by <code>a.swap(b)</code>.
</p>
</dd>
</dl>
</blockquote>
    
<h4><a name="syncstream.syncbuf.mfun"><code>basic_syncbuf</code> member functions [syncstream.syncbuf.mfun]</a></h4>

<blockquote class="stdins">
<dl>

<dt>
<code>bool emit();</code>
</dt>
<dd>

<p><i>Effects:</i>
Atomically transfers the contents of the internal buffer
to the stream buffer <code>*wrapped</code>,
so that they appear in the output stream as a contiguous sequence of characters.
If and only if a call was made to <code>this-&gt;sync()</code>,&nbsp;  
<code>wrapped-&gt;pubsync()</code> is called.
</p>

<p><i>Returns:</i> true if <code>wrapped != nullptr</code>, all of the
buffered characters were successfully transferred, and the call
to <code>wrapped-&gt;pubsync()</code> (if any) succeeded; otherwise false.
</p>
     
<p><i>Synchronization:</i>
All <code>emit()</code> calls transferring characters 
to the same stream buffer object
appear to execute in a total order consistent with <i>happens-before</i> 
where each <code>emit()</code> call <i>synchronizes-with</i> subsequent 
<code>emit()</code> calls in that total order.
</p>

<p><i>Remarks:</i>
May call member functions of <code>wrapped</code> while holding a lock
uniquely associated with <code>wrapped</code>.
</p>
</dd>

<dt>
<code>streambuf_type* get_wrapped() const noexcept;</code>
</dt>
<dd>
<p><i>Returns:</i>
<code>wrapped</code>.
</p>
</dd>

<dt>
<code>allocator_type get_allocator() const noexcept;</code>
</dt>
<dd>
<p><i>Returns:</i>
A copy of the allocator set in the constructor or from assignment.
</p>
</dd>
</dl>
</blockquote>

<h4><a name="syncstream.syncbuf.virtuals"><code>basic_syncbuf</code> overridden virtual functions [syncstream.syncbuf.virtuals]</a></h4>

<blockquote class="stdins">
<dl>
<dt>
<code>int sync() override;</code>
</dt>

<dd>
<p><i>Effects:</i>
Record the fact that user desires that the wrapped buffer be flushed.
The actual flush is delayed until a call to <code>emit()</code>.
</p><p>

</p><p><i>Returns:</i> 0.
</p></dd>  
<!--
<dt>
<code>int_type overflow(int_type c = traits::eof()) override;</code>
</dt>

<dd>

<p>
<i>Effects:</i> Appends the character designated by c to the output sequence,
if possible, in one of the following ways (in order):
</p>
<ul class="dash">
<li>
  If <code>wrapper == nullptr</code>, signals failure by
  returning <code>traits::eof()</code>.
</li>
<li>
  If <code>traits::eq_int_type(c, traits::eof())</code> returns false and if
  either the output sequence has a write position available or the function
  makes a write position available by allocating storage. The function
  then calls <code>sputc(c)</code> and signals success by returning c.
</li>
<li>
  If <code>traits::eq_int_type(c, traits::eof())</code> returns true, there is
  no character to append. Signals success by returning a value other than
  <code>traits::eof()</code>.
</li>
</ul>

<p>
<i>Returns:</i> <code>traits::eof()</code> to indicate failure.
</p>
</dd>
-->

</dl>
</blockquote>


<h3><a name="syncstream.osyncstream">Class template <code>basic_osyncstream</code> [syncstream.osyncstream]</a></h3>

<blockquote class="stdins">
<pre><code>template &lt;class charT,
          class traits,
          class Allocator&gt;
class basic_osyncstream
  : public basic_ostream&lt;charT,traits&gt;
{
public:
  using char_type      = charT;
  using int_type       = typename traits::int_type;
  using pos_type       = typename traits::pos_type;
  using off_type       = typename traits::off_type;
  using traits_type    = traits;
  using allocator_type = Allocator;
  using streambuf_type = basic_streambuf&lt;charT,traits&gt;;
  using syncbuf_type   = basic_syncbuf&lt;charT,traits, Allocator&gt;;

  explicit basic_osyncstream(streambuf_type *obuf)
  :basic_osyncstream(obuf, Allocator{});
  explicit basic_osyncstream(basic_ostream&lt;charT,traits&gt; &amp;os)
  :basic_osyncstream(os,Allocator{});
  basic_osyncstream(streambuf_type *obuf, Allocator const &amp;allocator);
  basic_osyncstream(basic_ostream&lt;charT,traits&gt; &amp;os, Allocator const &amp;allocator);
  basic_osyncstream(basic_osyncstream&amp;&amp;);
  ~basic_osyncstream();
  basic_osyncstream&amp; operator=(basic_osyncstream&amp;&amp;);
  void emit();
  streambuf_type* get_wrapped() const noexcept;
  syncbuf_type*   rdbuf() const noexcept override { return &amp;sb ; }
private:
  syncbuf_type sb; // <i>exposition only</i>
};
</code></pre>

<p>
<code>Allocator</code> shall meet the allocator requirements [allocator.requirements]. 
</p>

<p>
[<i>Example:</i>
Use a named variable within a block statement for streaming
across multiple statements.
</p>
<pre class="example"><code>{
  osyncstream bout(cout);
  bout &lt;&lt; "Hello, ";
  bout &lt;&lt; "World!";
  bout &lt;&lt; endl; // flush is noted
  bout &lt;&lt; "and more!\n";
} // characters are transferred and cout is flushed
</code></pre>
<p>
<i>end example</i>]
</p>

<p>
[<i>Example:</i>
Use a temporary object for streaming within a single statement. 
<code>cout</code> is not flushed.
</p>
<pre class="example"><code>osyncstream(cout) &lt;&lt; "Hello, " &lt;&lt; "World!" &lt;&lt; '\n';</code></pre>
<p>
<i>end example</i>]
</p>

</blockquote>


<h4><a name="synstream.osyncstream.ctor"><code>osyncstream</code> Constructor [syncstream.osyncstream.ctor]</a></h4>

<blockquote class="stdins">

<dl>
<dt>
<code>basic_osyncstream(streambuf_type *buf, Allocator const &amp;allocator);</code>
</dt>
<dd>

<p><i>Effects:</i>
Initializes <code>sb</code> from <code>buf</code> and <code>allocator</code> and initializes
the base class with <code>basic_ostream(&amp;sb)</code>.
<!--which will be the final destination of characters in <code>out</code>. 
If 
the stored stream buffer pointer 
 <code>out == nullptr</code>
 output operations on 
<code>*this</code> fail.
A copy of <code>allocator</code> is used to allocate memory 
for the stream's own internal buffer, if any.
</p>

<p>
Constructs a stream buffer object [stream.buffers].
-->
</p>
<p>
[<i>Note:</i>
If wrapped stream buffer pointer refers to a user provided stream buffer 
then its implementation must
be aware that its member functions might be called from <code>emit()</code> 
while a lock is held.
<i>end note</i>]
</p>

<p><i>Postconditions:</i>
<code>get_wrapped() == buf</code>
</p>

</dd><dt>
<code>basic_osyncstream(basic_ostream&lt;charT,traits&gt;&amp; os, Allocator const &amp;allocator);</code>
</dt>
<dd>
<p><i>Effects:</i>
<code>basic_osyncstream(os.rdbuf(),a)</code>
</p></dd>

<dt>
<code>basic_osyncstream(basic_osyncstream&amp;&amp; other);</code>
</dt>
<dd>

<p><i>Effects:</i>
Move constructs from <code>other</code>. This is accomplished by
move constructing the base class, and the contained <code>basic_syncbuf sb</code>.
Next <code>basic_ostream&lt;charT, traits&gt;::set_rdbuf(&amp;sb)</code> is called
to install the <code>basic_syncbuf sb</code>. <!-- almost directly from Pablo -->

<!--First, the state necessary to perform <code>os.emit()</code> is moved to <code>*this</code>.
Then <code>os.out = nullptr</code>.
[<i>Note:</i>
This disassociates <code>os</code> from its wrapped stream buffer ensuring 
destruction of <code>os</code> produces no output.
&mdash;<i>end note</i>]
</p>-->
</p><p><i>Postconditions:</i>
The value returned by <code>this-&gt;get_wrapped()</code> is the value 
returned by <code>os.get_wrapped()</code> prior to calling this constructor. 
<code>nullptr == os.get_wrapped()</code>.--&gt;
</p>

</dd>

</dl>

</blockquote>


<h4><a name="synstream.osyncstream.dtor"><code>osyncstream</code> Destructor [synstream.osyncstream.dtor]</a></h4>

<blockquote class="stdins">

<dl>

<dt><code>~basic_osyncstream();</code></dt>
<dd>

<p><i>Effects:</i>
Calls <code>emit()</code>.
</p>

</dd>
</dl>

</blockquote>
<h4><a name="synstream.osyncstream.assign"><code>osyncstream</code> Assignment [synstream.osyncstream.assign]</a></h4>

<blockquote class="stdins">

<dl>

<dt>
<code>basic_osyncstream&amp; operator=(basic_osyncstream&amp;&amp; other);</code>
</dt>
<dd>

<p><i>Effects:</i>
First, calls <code>this-&gt;emit()</code>. 
Move assigns <code>sb</code> from <code>other.sb</code>.
[<i>Note:</i>
This disassociates <code>other</code> from its wrapped stream buffer ensuring 
destruction of <code>other</code> produces no output.
<i>end note</i>]</p>

<p><i>Postcondition:</i>
Primarily, <code>nullptr == other.get_wrapped()</code>. 

Also, <code>get_wrapped()</code> returns the value previously returned by 
<code>other.get_wrapped()</code>.
</p>

</dd>
</dl>

</blockquote>



<h4><a name="syncstream.osyncstream.mfun"><code>osyncstream</code> Member Functions [syncstream.osyncstream.mfun]</a></h4>

<blockquote class="stdins">

<dl>

<dt><code>void emit();</code></dt>
<dd>

<p><i>Effects:</i>
Calls <code>sb.emit()</code>. If this call returns <code>false</code>,
calls <code>setstate(ios::badbit)</code>.
<!--
Transfers the contents of the internal stream buffer
to the stream buffer <code>*out</code>,
so that they appear in the output stream as a contiguous sequence of characters.
If and only if a flush was requested on <code>*this</code>,&nbsp; 
<code>out->pubsync()</code> is called on the stream buffer obtained in the constructor. 
A failure in transferring the characters or flushing calls, such as <code>out</code>
having the value <code>nullptr</code>, result in <code>setstate(ios::badbit)</code>.
-->
</p>
<!--
[<i>Note:</i>
A flush on a <code>basic_osyncstream</code>
does not flush the <code>basic_osyncstream</code> to the stream buffer,
but rather flushes the stream buffer
after transfering the contents of the <code>basic_osyncstream</code>
to the stream buffer.
-->
[<i>Example:</i>
A flush on a <code>basic_osyncstream</code> does not flush immediately:
<pre class="example"><code>{
  osyncstream bout(cout);
  bout &lt;&lt; "Hello," &lt;&lt; '\n'; // no flush
  bout.emit(); // characters transferred; cout <em>not</em> flushed
  bout &lt;&lt; "World!" &lt;&lt; endl; // flush noted; bout <em>not</em> flushed
  bout.emit(); // characters transferred; cout <em>flushed</em>
  bout &lt;&lt; "Greetings." &lt;&lt; '\n'; // no flush
} // characters transferred; cout <em>not</em> flushed</code>
</pre>
<p>
<i>end example</i>]
<!--
&mdash;<i>end note</i>]
-->
</p>
<!--
<p><i>Synchronization:</i>
All <code>emit()</code> calls transferring characters 
to the same 
stream buffer object
appear to execute in a total order consistent with <i>happens-before</i> 
where each <code>emit()</code> call <i>synchronizes-with</i> subsequent 
<code>emit()</code> calls in that total order.
</p>
<p><i>Remarks:</i>
May hold a lock uniquely associated with the underlying 
stream buffer object obtained in the constructor while transferring characters.
</p>
-->
<p>
[<i>Example:</i>
The function <code>emit()</code> can be used to catch exceptions 
from operations on the underlying stream.
</p>
<pre class="example"><code>{
  osyncstream bout(cout);
  bout &lt;&lt; "Hello, " &lt;&lt; "World!" &lt;&lt; '\n';
  try {
    bout.emit();
  } catch ( ... ) {
    // stuff
  }
}</code>
</pre>
<p>
<i>end example</i>]
</p>

</dd>

<dt><code>streambuf_type* get_wrapped() const noexcept;</code></dt>
<dd>

<p><i>Returns:</i>
<code>sb.get_wrapped()</code>
</p>

<p>[<i>Example:</i>
Obtaining the wrapped stream buffer with <code>get_wrapped()</code> 
allows wrapping it again with an <code>osyncstream</code>.
For example,
</p>
<pre class="example"><code>{
  osyncstream bout1(cout);
  bout1 &lt;&lt; "Hello, ";
  {
    osyncstream bout2(bout1.get_wrapped());
    bout2 &lt;&lt; "Goodbye, " &lt;&lt; "Planet!" &lt;&lt; '\n';
  }
  bout1 &lt;&lt; "World!" &lt;&lt; '\n';
}</code></pre>
<p>
produces the <em>uninterleaved</em> output
</p>
<pre class="example"><code>Goodbye, Planet!
Hello, World!
</code></pre>
<p>
<i>end example.</i>]
</p>


</dd>


</dl>

</blockquote>

<h2><a name="implementation">Implementation</a></h2>

<p>
Two example implementations are available on 
<a href="https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/Test_basic_osyncstream">
github.com/PeterSommerlad/SC22WG21_Papers/workspace/Test_basic_osyncstream</a> and
<a href="https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/p0053_basic_osyncstreambuf">
https://github.com/PeterSommerlad/SC22WG21_Papers/tree/master/workspace/p0053_basic_osyncstreambuf</a>.
</p>
<p>The latter actually implements almost all of the mechanics in a stream buffer
as proposed by Pablo Halpern where the first one is my original implementation with 
most of the mechanics stuck in the basic_osyncstream.
</p>


<h2><a name="Revisions">Revisions</a></h2>
<p>
This paper revises
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0053r3.html">
P0053R3 C++ Synchronized Buffered Ostream</a>
</p>
<ul>

<li><p>
Takes input from Pablo Halpern and re-instantiate the stream buffer that performs the synchronization.
</p></li>

<li><p>
Split the constructors with a defaulted allocator parameter to one single-argument one being explicit
and one non-explicit taking 2 arguments.
</p></li>
</ul>


<p>
This paper revises
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0053r2.html">
P0053R2 C++ Synchronized Buffered Ostream</a>
</p>
<ul>

<li><p>
Remove the "may construct a mutex" notes.
</p></li>

<li><p>
Remove "may destroy mutex" notes.
</p></li>

<li><p>
Clarify osyncstream flush behavior in an example.
</p></li>

<li><p>
Make minor editorial fixes.
</p></li>

</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0053r2.html">
P0053R2</a> revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0053r1.html">
P0053R1 C++ Synchronized Buffered Ostream</a>
</p>
<ul>
<li>
<p>
Provide a typedef for the wrapped stream buffer and use it to shorten the specification 
as suggested by Daniel Krgler.
</p>
</li>
<li>
<p>
Provide move construction and move assignment and specify the moved-from state to be 
detached from the wrapped stream buffer.
</p>
</li>
<li>
<p>
Rename <code>get()</code> to <code>rdbuf_wrapped()</code> and provide noexcept specification.
</p>
</li>
<li>
<p>
Changed to explicitly rely on wrapping a stream buffer, 
instead of an ostream object and adjust explanations accordingly.
</p>
</li>
</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0053r1.html">
P0053R1</a> revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0053r0.html">
P0053R0 C++ Synchronized Buffered Ostream</a>
</p>
<ul>
<li>
<p>
Add remark to note that exchanging the stream buffer while the stream is wrapped causes
undefined behavior and added a note to warn stream buffer implementers about the lock 
being held in <code>emit()</code>. Call setstate(badbit) if IO errors occur in emit().
</p>
</li>
<li>
<p>
Replace code references to <code>basic_streambuf</code> by the 
term <i>stream buffer</i> introduced in [stream.buffers].
</p>
</li>
<li>
<p>
Provide an example implementation.
</p>
</li>
<li>
<p>
The lock is to be associate to the underlying <code>basic_streambuf</code> instead of the <code>basic_stream</code>.
</p>
</li>
<li>
<p>
Added an <code>Allocator</code> constructor parameter.
</p>
</li>
<li>
<p>
Moves destructor example to <code>emit()</code>.
</p>
</li>
<li>
<p>
Clarifies wording about synchronization and flushing (several times).
</p>
</li>
<li>
<p>
List the new header in corresponding table.
</p>
</li>
<li>
<p>
Provide type aliases in <code>&lt;iosfwd&gt;</code>.
</p>
</li>
<li>
<p>
Removed copy constructor in favor of providing <code>get()</code>.
</p>
</li>
<li>
<p>
Notify that move construction and assignment is deleted.
</p>
</li>
<li>
<p>
Moved class noteflush_streambuf into an implementation note.
</p>
</li>
<li>
<p>
Add a design subsection that states that
a header test is a sufficient feature test.
</p>
</li>
</ul>


<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0053r0.html">
P0053R0</a> revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/N4187.html">
N4187 C++ Ostream Buffers</a>
</p>

<ul>

<li><p>
Updated introduction with recent history.
</p></li>

<li><p>
Rename <code>ostream_buffer</code> to <code>osyncstream</code>
to reflect its appearance is more like a stream than like a buffer.
</p></li>

<li><p>
Add an example of using <code>osyncstream</code> as a temporary object.
</p></li>

<li><p>
Add an example of a <code>osyncstream</code>
constructed with another <code>osyncstream</code>.
</p></li>

<li><p>
Clarify the behavior of nested <code>osyncstream</code> executions.
</p></li>

<li><p>
Clarify the behavior of exceptions
occuring with the <code>osyncstream</code> destructor.
</p></li>

<li><p>
Clarify the deferral of flush from the 
<code>osyncstream</code>'s <code>streambuf</code>
to the final <code>basic_ostream</code>.
</p></li>

<li><p>
Limit the number of references to <code>noteflush_stringbuf</code>
in anticipation of the committee removing it from the specification.
</p></li>

<li><p>
Rename <code>noteflush_stringbuf</code>
to <code>noteflush_streambuf</code> to hide possible implementation details.
</p></li>

<li><p>
Change the base class of <code>noteflush_streambuf</code>
from <code>basic_stringbuf</code> to <code>basic_streambuf</code>.
</p></li>

</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4187.html">
N4187</a>
revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4069.html">
N4069 C++ Ostream Buffers</a>
</p>

<ul>
<li><p>
Added note to sync as suggested by BSI via email.
</p></li>
</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n4069.html">
N4069</a>
revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3978.html">
N3978 C++ Ostream Buffers</a>
</p>

<ul>

<li><p>
Added a Design section.
</p></li>

<li><p>
Clarify the reference capturing behavior
of the <code>ostream_buffer</code> constructors.
</p></li>

<li><p>
Added noexcept and const as appropriate to members.
</p></li>

<li><p>
Added note on throwing wrapped streams.
</p></li>

<li><p>
Change the
<code>noteflush_stringbuf</code>
public member variable
<code>needsflush</code>
to a public member query function <code>flushed</code>.
</p></li>

<li><p>
Removed the public member function <code>noteflush_stringbuf::clear</code>.
</p></li>

<li><p>
Minor synopsis formatting changes.
</p></li>

<li><p>
Incorporated feedback from SG1 and Dietmar Khl in specific in Rapperswil.
</p></li>
</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2014/n3978.html">
N3978</a> revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3892.html">
N3892 C++ Ostream Buffers</a>
</p>

<ul>

<li><p>
Flush the ostream if and only if the <code>ostream_buffer</code> was flushed.
</p></li>

<li><p>
Add the <code>clear_for_reuse</code> function.
</p></li>

<li><p>
Change the design from inheriting from <code>basic_ostream</code>
to using a <code>noteflush_stringbuf</code>,
which is a slightly modified <code>basic_stringbuf</code>.
The modification is to note the flush rather than act upon it.
</p></li>

</ul>

<p>
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3892.html">
N3892</a> revised
<a href="http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3750.html">
N3750 C++ Ostream Buffers</a>
</p>

<ul>

<li><p>
Change name to <code>basic_ostream_buffer</code>
and add the usual typedefs.
</p></li>

<li><p>
Change interface to inherit from <code>basic_ostringstream</code>
rather than provide access to a member of that type.
</p></li>

<li><p>
Add a Revisions section.
</p></li>

</ul>


<h2><a name="References">References</a></h2>

<dl>

<dt><a name="PSL">[PSL]</a></dt>
<dd>
<cite>The Open Group Base Specifications Issue 6,
IEEE Std 1003.1, 2004 Edition</cite>,
functions, flockfile,
<a href="http://pubs.opengroup.org/onlinepubs/009695399/functions/flockfile.html">
http://pubs.opengroup.org/onlinepubs/009695399/functions/flockfile.html</a>
</dd>

</dl>




</body></html>