Abstraction for External Representations


Synopsis

#include <streambuf>

namespace std {

  template <typename cT, typename traits = char_traits<cT> >
  class basic_streambuf
  {
  public:
    typedef cT                        char_type;
    typedef traits                    traits_type;
    typedef typename traits::int_type int_type;
    typedef typename traits::pos_type pos_type;
    typedef typename traits::off_type off_type;

    virtual ~basic_streambuf();

    // locale access:
    locale pubimbue(locale const& loc);
    locale getloc() const;

    // buffer and position handling:
    basic_streambuf* pubsetbuf(char_type* buf, streamsize n);
    pos_type         pubseekoff(off_type off, ios_base::seekdir dir, ios_base::openmode which);
    pos_type         pubseekpos(pos_type pos, ios_base::openmode which);
    int              pubsync();

    // get area:
    streamsize in_avail();
    int_type   snextc();
    int_type   sbumpc();
    int_type   sgetc();
    streamsize sgetn(char_type* buf, streamsize n);
    int_type   sputbackc(char_type c);
    int_type   sungetc();

    // put area:
    int_type   sputc(char_type c);
    streamsize sputn(char_type const* buf, streamsize n);

  protected:
    basic_streambuf]();

    // locale, buffer, and position handling:
    virtual void             imbue(locale const& loc);
    virtual basic_streambuf* setbuf(char_type* buf, streamsize n);
    virtual pos_type         seekoff(off_type offset, ios_base::seekdir dir, ios_base::openmode which);
    virtual pos_type         seekpos(pos_type position, ios_base::openmode which);
    virtual int              sync();

    // get area:
    char_type*         eback() const;
    char_type*         gptr() const;
    char_type*         egptr() const;
    void               gbump(streamsize n);
    void               setg(char_type* beg, char_type* cur, char_type* end);
    virtual int        showmanyc();
    virtual streamsize xsgetn(char_type* buf, streamsize n);
    virtual int_type   underflow();
    virtual int_type   uflow();
    virtual int_type   pbackfail(int_type c = traits_type::eof());

    // put area:
    char_type*         pbase() const;
    char_type*         pptr() const;
    char_type*         epptr() const;
    void               pbump(streamsize n);
    void               setp(char_type* beg, char_type* end);
    virtual streamsize xsputn(char_type const* buf, streamsize n);
    virtual int_type   overflow(int_type c);
  };

  typedef basic_streambuf<char> streambuf;
  typedef basic_streambuf<wchar_t> wstreambuf;
} // namespace std

Description

The template class basic_streambuf is the workhorse of the IOStream library: This class provides the interface to read characters from and write characters to some sequence. Although the actual reading and writing is done in derived classes, basic_streambuf still provides the functionality necessary for buffering. However, whether the stream buffer in use actually buffers input and/or output is transparent to the user of the class. There are two functions which aid in buffer maintainance, namely pubsync() and pubsetbuf(), but the effect, if any, is dependent on the concrete stream buffer type. The public interface of basic_streambuf provides mainly functions for reading and writing of characters and for manipulation of the read and write positions within the stream.

The protected interface provides the overrideable function and all necessary functions for buffer manipulation. Using these functions it is fairly easy to create a stream buffer accessing a new external representation like a GUI window, a compressed file, a socket, you name it. When creating a new stream buffer, it can be decided whether the stream is buffered or not. However, there is a fair chance that buffered I/O is faster, at least when using the standard specializations for basic_streambuf, because in this case the public interface can be bypassed, effectively hoisting certain tests out of the inner loop. On the other hand, especially for filtering stream buffers (i.e. stream buffers using another stream buffer doing the actual I/O but processing the read or written characters e.g. to compress/uncompress them), buffering can introduce synchronization problems when the sequence underlying a stream buffer is used using multiple stream buffers or even multiple programs.

Public Interface

The public interface of basic_streambuf is fairly simple but still rarely used directly: Normally, it is sufficient to have basic_istream read characters from and basic_ostream write characters to the the stream buffer underlying the corresponding stream. ... and even if the stream buffer is used directly, it is often accessed using istreambuf_iterator or ostreambuf_iterator. Unless you have specific needs, this is probably sufficient but in some situations it may be more convenient or more efficient to use the stream buffer directly.

In the following sections, an error might be indicated by an exception being thrown. This is not always explicitly mentioned. Instead, only the error reporting mechanism not using exceptions is described but it should be kept in mind that all of these functions might throw an exception to indicate an error.

The stream buffer functions often use traits::eof() to indicate an error or an invalid character. To represent either a character value of the value traits::eof(), the type int_type (which is a typedef for typename traits::int_type) is used. It is thus often necessary to convert between the character type (char_type) and the integer type int_type. The conversions are done using traits::to_char_type() and traits::to_int_type().

Writing Characters

Writing characters to a stream buffer is extremely simple: Using sputc() you can send individual characters and with sputn() you can send character sequences. sputc() returns traits::eof() if an error occured and sputn() returns the number of characters written which can be used if writing of all characters was successful. Note, that due to buffering character do not necessarily appear immediately in the underlying sequence. To let them appear you might have to call pubsync() to flush the buffer.

Reading Characters

Input can be as simple as output: sbumpc() reads a single character or returns traits::eof() if it fails to do so. The function sgetn() can be used to read a sequence of characters. This function returns the number of characters for error checking. However, the needs when reading characters are often more complex. For example, during parsing of input, it is often necessary to first have a look at the character without extracting it from the sequence. The function sgetc() can be used for this. If the inspected character matches the expected format, it can be normally be extracted and the next character is to be inspected. This is what the function snextc() is for: It is basically a sbumpc() followed by a sgetc().

See Also


Copyright © 1999 Dietmar Kühl (dietmar.kuehl@claas-solutions.de)
Claas Solutions GmbH