ISO/IEC JTC1 SC22 WG21 N4187 - 2014-10-08
Lawrence Crowl, Lawrence@Crowl.org
Peter Sommerlad, Peter.Sommerlad@hsr.ch
Introduction
Solution
Design
Wording
27.8.1 Overview [string.stream.overview]
27.8.8 Class template basic_ostream_buffer
[ostream.buffer]
27.8.8.1 Constructor [ostream.buffer.ctor]
27.8.8.2 Destructor [ostream.buffer.dtor]
27.8.8.2 Member Functions [ostream.buffer.mfun]
27.8.9 Class template noteflush_stringbuf
[ostream.noteflush.stringbuf]
27.8.9.1 Member Functions [ostream.noteflush.stringbuf.mfun]
Revisions
References
At present, 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.
N3535 C++ Stream Mutexes 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.
N3678 C++ Stream Guards proposed a standard mechanism for batching operations on a stream. That batching may be implemented as mutexees, 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.
N3665 Uninterleaved Sring Output Streaming
proposed making streaming of strings of length less than BUFSIZ
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.
The general consensus in the July 2013 meeting of the Concurrency Study Group was that buffering should be explicit.
N3978 proposed such an explicit buffering. This updated paper fixes some of the issues raised by SG1 and Daniel Krügler.
We propose a basic_ostream_buffer
,
that provides
buffering output operations for a wrapped stream.
The basic_ostream_buffer
,
will atomically transfer the contents
of the internal stream buffer noteflush_stringbuf
to an ostream
on destruction of the basic_ostream_buffer
.
The transfer on destruction simplifies the code and ensures at least some output in the presence of an exception.
The intent is that the basic_ostream_buffer
is an automatic-duration variable
with a relatively small scope
which constructs the text to appear uninterleaved.
For example,
....
{
std::ostream_buffer bout(std::cout);
bout << "Hello, " << "World!" << std::endl;
}
....
We follow typical stream conventions
of basic_
prefixes and typedefs.
The constructors for ostream_buffer
take non-const references
to either a basic_ostream
or a basic_ostream_buffer
.
This non-const reference indicates that
the destruction of the buffer
may write to the stream associated with the argument.
The constructors for ostream_buffer
from another ostream_buffer
is not a copy constructor,
but an attachment to the argument buffer.
This approach enables nested
passing an ostream_buffer
to a function expecting an ostream
,
which then in turn uses an ostream_buffer
on that ostream
The wording below
permits implementation of basic_ostream_buffer
with either a stream_mutex
from
N3535
or with implementations suitable for
N3665,
e.g. with Posix file locks
[PSL]
This wording is relative to N3691.
Edit within paragraph 1 as follows.
The header
<sstream>
defines four class templates and eight types that associate stream buffers with objects of classbasic_string
, as described in 21.3. It also defines a class templatebasic_ostream_buffer
to buffer output and pass the buffered content into anostream
on destruction or explicit request by callingclear_for_reuse()
in one consecutive sequence.
Edit within the synopsis as follows.
template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_stringstream; typedef basic_stringstream<char> stringstream; typedef basic_stringstream<wchar_t> wstringstream; template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class basic_ostream_buffer; typedef basic_ostream_buffer<char> ostream_buffer; typedef basic_ostream_buffer<wchar_t> wostream_buffer; template <class charT, class traits = char_traits<charT>, class Allocator = allocator<charT> > class noteflush_stringbuf; typedef basic_ostream_buffer<char> ostream_buffer; typedef basic_ostream_buffer<wchar_t> wostream_buffer;
basic_ostream_buffer
[ostream.buffer]Add a new section.
template <class charT, class traits = std::char_traits<charT>, class Allocator = std::allocator<charT> > class basic_ostream_buffer : public std::basic_ostream<charT,traits,Allocator> { public: typedef charT char_type; typedef traits traits_type; typedef typename traits_type::int_type int_type; typedef typename traits_type::pos_type pos_type; typedef typename traits_type::off_type off_type; typedef Allocator allocator_type; basic_ostream_buffer(basic_ostream_buffer &osb); explicit basic_ostream_buffer(std::basic_ostream<charT,traits> &os); ~basic_ostream_buffer(); void clear_for_reuse(); noteflush_stringbuf
*rdbuf() const; private: std::basic_ostream<chart,traits>& out; // exposition only }; The class template
basic_ostream_buffer
supports buffering into anoteflush_stringbuf
and then indivisibly transfering the contents of thenoteflush_stringbuf
to abasic_ostream
.[Example:
....{ std::ostream_buffer bout(std::cout); bout << "Hello, " << "World!" << std::endl; }
....—end example]
[Note: If the underlying stream can throw exceptions, use
clear_for_reuse()
to catch those, otherwise an exception of the underlying stream mayterminate()
your program. —end note]
Add a new section.
basic_ostream_buffer(basic_ostream_buffer &osb);
Effects: Stores a reference to the
basic_ostream
that is the base class ofbasic_ostream_buffer
, and which will latter be the output stream. Constructs anoteflush_stringbuf
. May construct a mutex.[Note: This overload exists to allow wrapping a
basic_ostream_buffer
again with abasic_ostream_buffer
. end note.]basic_ostream_buffer(std::basic_ostream<charT,traits> &os);
Effects: Stores a reference to the
basic_ostream
, which will latter be the output stream. Constructs anoteflush_stringbuf
. May construct a mutex.
Add a new section.
~basic_ostream_buffer() noexcept;
Effects:
clear_for_reuse()
. May destroy a lock.Synchronization: May or may not acquire a mutex while transfering characters.
Add a new section.
void clear_for_reuse();
Effects: Transfers the contents of the
noteflush_stringbuf
to the stream specified in the constructor as an indivisible uninterleaved sequence of characters, with respect to all other uses ofbasic_ostream_buffer
on that stream. If and only if a flush was requested on thenoteflush_stringbuf
, the stream will be flushed.Postcondition:
!rdbuf()->flushed() && rdbuf()->str().empty()
.Synchronization: May or may not acquire a mutex while transfering characters.
noteflush_stringbuf
[ostream.noteflush.stringbuf]Add a new section.
template <class charT, class traits, class Allocator> class noteflush_stringbuf : public std::basic_stringbuf<charT,traits,Allocator> { bool needs_flush_=false; // exposition only public: using std::basic_stringbuf<charT, traits, Allocator>::basic_stringbuf; protected: bool flushed() const noexcept { return needs_flush_;} // exposition only virtual int sync(); };
The class template
noteflush_stringbuf
behaves as abasic_stringbuf
except that flushes of the stream using it, which incur in calling thesync()
member function are noted instead of a no-op.
Add a new section.
int sync() noexcept;
Effects: Notes the occurence of a flush within the object.
Postcondition:
flushed()
.[Note: The postcondition of
sync()
ensures that a subsequent call toclear_for_reuse()
in the owningbasic_ostream_buffer
will flush the stream being buffered. -- end note]Returns:
0
.
This paper revises N4069 C++ Ostream Buffers
N4069 paper revised N3978 C++ Ostream Buffers
Added a Design section.
Clarify the reference capturing behavior
of the ostream_buffer
constructors.
Added noexcept and const as appropriate to members.
Added note on throwing wrapped streams.
Change the
noteflush_stringbuf
public member variable
needsflush
to a public member query function flushed
.
Removed the public member function noteflush_stringbuf::clear
.
Minor synopsis formatting changes.
Incorporated feedback from SG1 and Dietmar Kühl in specific in Rapperswil.
N3978 revised N3892 C++ Ostream Buffers
Flush the ostream if and only if the ostream_buffer
was flushed.
Add the clear_for_reuse
function.
Change the design from inheriting from basic_ostream
to using a noteflush_stringbuf
,
which is a slightly modified basic_stringbuf
.
The modification is to note the flush rather than act upon it.
N3892 revised N3750 C++ Ostream Buffers
Change name to basic_ostream_buffer
and add the usual typedefs.
Change interface to inherit from basic_ostringstream
rather than provide access to a member of that type.
Add a Revisions section.