# C++ Ostream Buffers

ISO/IEC JTC1 SC22 WG21 N4069 - 2014-06-18

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

## Introduction

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.

## Solution

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;
    }
    ....

## Design

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 too 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]

## Wording

This wording is relative to N3691.

### 27.8.1 Overview [string.stream.overview]

Edit within paragraph 1 as follows.

> The header `<sstream>` defines four class templates and eight types that associate stream buffers with objects of class `basic_string`, as described in 21.3. It also defines a class template `basic_ostream_buffer` to buffer output and pass the buffered content into an `ostream` on destruction or explicit request by calling `clear_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;

### 27.8.8 Class template `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 a `noteflush_stringbuf` and then indivisibly transfering the contents of the `noteflush_stringbuf` to a `basic_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 may `terminate()` your program. —end note]

### 27.8.8.1 Constructor [ostream.buffer.ctor]

Add a new section.

> `basic_ostream_buffer(basic_ostream_buffer &osb);`

>   Effects: Stores a reference to the `basic_ostream` that is the base class of `basic_ostream_buffer`, and which will latter be the output stream. Constructs a `noteflush_stringbuf`. May construct a mutex.

>   [Note: This overload exists to allow wrapping a `basic_ostream_buffer` again with a `basic_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 a `noteflush_stringbuf`. May construct a mutex.

### 27.8.8.2 Destructor [ostream.buffer.dtor]

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.

### 27.8.8.3 Member Functions [ostream.buffer.mfun]

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 of `basic_ostream_buffer` on that stream. If and only if a flush was requested on the `noteflush_stringbuf`, the stream will be flushed.

>   Postcondition: `!rdbuf()->flushed() && rdbuf()->str().empty()`.

>   Synchronization: May or may not acquire a mutex while transfering characters.

### 27.8.9 Class template `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 a `basic_stringbuf` except that flushes of the stream using it, which incur in calling the `sync()` member function are noted instead of a no-op.

### 27.8.9.1 Member Functions [ostream.noteflush.stringbuf.mfun]

Add a new section.

> `int sync() noexcept;`

>   Effects: Notes the occurence of a flush within the object.

>   Postcondition: `flushed()`.

>   Returns: `0`.

## Revisions

ISO/IEC JTC1 SC22 WG21 N4069 - 2014-06-18

This paper revises 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.

## References

[PSL]
  The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition, functions, flockfile, http://pubs.opengroup.org/onlinepubs/009695399/functions/flockfile.html