    How complex would things get if we decided to use a buffer of
substantial size? Not that complex. The following class allows us to specify
the size of a buffer, but apart from that it is basically the same class as
tt(IFdStreambuf) developed in the previous section. To make things a bit more
interesting, in the class ti(IFdNStreambuf) developed here, the member
hi(xsgetn)tt(streambuf::xsgetn) is also overridden, to optimize reading a
series of characters. Also a default constructor is provided that can be used
in combination with the tt(open) member to construct an tt(istream) object
before the file descriptor becomes available. In that case, once the
descriptor becomes available, the tt(open) member can be used to initiate
the object's buffer. Later, in section ref(FORK), we'll encounter such a
situation.

    To save some space, the success of various calls was not checked. In `real
life' implementations, these checks should of course not be omitted. The
class tt(IFdNStreambuf) has the following characteristics:
    itemization(
    it() Its member functions use low-level functions operating on file
descriptors. So apart from tt(streambuf) the tthi(unistd.h) header file must
have been read by the compiler before its member functions can be compiled.
    it() As usual, it is derived from hi(streambuf)tt(std::streambuf).
    it() Like the class tt(IFdStreambuf) (section ref(IFDBUF)), its data
members are protected. Since the buffer's size is configurable, this size is
kept in a dedicated data member, tt(d_bufsize):
            verbinclude(//CLASS examples/ifdnbuf.h)
    it() The default constructor does not allocate a buffer. It can be used
to construct an object before the file descriptor becomes known. A second
constructor simply passes its arguments to tt(open). tt(Open) will then
initialize the object so that it can actually be used:
            verbinclude(//CONS examples/ifdnbuf.h)
    it() Once the object has been initialized by tt(open), its destructor will
both delete the object's buffer and use the file descriptor to close the
device:
            verbinclude(//DESTR examples/ifdnbuf.h)
    Even though the device is closed in the above implementation this may not
always be desirable. In cases where the open file descriptor is already
available the intention may be to use that descriptor repeatedly, each time
using a newly constructed tt(IFdNStreambuf) object. It is left as an exercise
to the reader to change this class in such a way that the device may
optionally be closed. This approach was followed in, e.g., the
        url(Bobcat library)(http://fbb-git.gitlab.io/bobcat/).
        hi(Bobcat library)hi(http://fbb-git.gitlab.io/bobcat/)
    it() The tt(open) member simply allocates the object's buffer. It is
assumed that the calling program has already opened the device. Once the
buffer has been allocated, the base class member ti(setg) is used to ensure
that hi(eback) tt(streambuf::eback) hi(gptr) tt(streambuf::gptr) and hi(egptr)
tt(streambuf::egptr) return correct values:
            verbinclude(//OPEN examples/ifdnbuf.h)
    it() The overridden member tt(underflow) is implemented almost
identically to tt(IFdStreambuf)'s (section ref(IFDBUF)) member. The only
difference is that the current class supports buffers of larger
sizes. Therefore, more characters (up to tt(d_bufsize)) may be read from the
device at once:
            verbinclude(//UFLOW examples/ifdnbuf.h)
    it() Finally ti(xsgetn) is overridden. In a loop, tt(n) is reduced until
0, at which point the function terminates. Alternatively, the member returns
if tt(underflow) fails to obtain more characters. This member optimizes the
reading of series of characters. Instead of calling hi(sbumpc)
tt(streambuf::sbumpc) tt(n) times, a block of tt(avail) characters is copied
to the destination, using hi(gbump)tt(streambuf::gbump) to consume tt(avail)
characters from the buffer using one function call:
            verbinclude(//XSGETN examples/ifdnbuf.h)
    )
    The member function ti(xsgetn) is called by hi(sgetn)tt(streambuf::sgetn),
which is a tt(streambuf) member. Here is an example illustrating the use of
this member function with an tt(IFdNStreambuf) object:
        verbinclude(-a examples/ifdnbuf.cc)
