Listing 1: Class rangebuf

#include <streambuf>
#include <ios>
#include <algorithm>
#include <iterator>

template <class FwIter>
class rangebuf : public std::streambuf {
private:
  FwIter first;
  FwIter last;
  FwIter current;

  enum { bufsize = 128 };
  char buf[bufsize];

  void fill_buffer();

public:
  rangebuf(FwIter f, FwIter l);

protected:
  pos_type seekoff(off_type off, std::ios::seekdir way,
                   std::ios::openmode which);
  pos_type seekpos(pos_type pos, std::ios::openmode which);
  
  int underflow();
  int pbackfail(int c);
};

template <class FwIter>
rangebuf<FwIter>::rangebuf(FwIter f, FwIter l)
  : std::streambuf(),
    first(f), last(l), current(f)
{
  fill_buffer();
}

template <class FwIter>
void rangebuf<FwIter>::fill_buffer()
{
  ptrdiff_t len = std::distance(current, last);
  ptrdiff_t n = std::min(len, ptrdiff_t(bufsize));
  FwIter tmp = current;
  std::advance(tmp, n);
  std::copy(current, tmp, buf);
  setg(buf, buf, buf + n);
}

template <class FwIter>
int rangebuf<FwIter>::underflow() {
  std::advance(current, egptr() - eback());
  fill_buffer();
  return gptr() != egptr()
    ? static_cast<int>(static_cast<unsigned char>(*gptr()))
    : EOF;
}

template <class FwIter>
int rangebuf<FwIter>::pbackfail(int c) {
  if (gptr() == eback() && current != first) {
    FwIter tmp = first;
    std::advance(tmp, std::distance(first, current) - 1);
    current = tmp;
    fill_buffer();
    gbump(1);
  }

  if (gptr() == eback() || (c != EOF && c != *(gptr() - 1)))
    return EOF;
  else {
    gbump(-1);
    return static_cast<unsigned char>(*gptr());
  }
}

template <class FwIter>
std::streambuf::pos_type
rangebuf<FwIter>::seekoff(off_type off, std::ios::seekdir way,
                          std::ios::openmode which) {
  switch(way) {
  case std::ios::beg:
    return seekpos(pos_type(off), which);
  case std::ios::cur:
    return seekpos(pos_type(off + std::distance(first, current)),
                   which);
  case std::ios::end:
    return seekpos(pos_type(off + std::distance(first, last)), 
                   which);
  default:
    return pos_type(off_type(-1));
  }
}

template <class FwIter>
std::streambuf::pos_type
rangebuf<FwIter>::seekpos(pos_type pos, std::ios::openmode which) {
  if (which != std::ios::in)
    return pos_type(off_type(-1));

  off_type offset = off_type(pos);
  if (offset < 0 || offset > std::distance(first, last))
    return pos_type(off_type(-1));

  FwIter tmp = first;
  std::advance(tmp, offset);
  current = tmp;
  fill_buffer();

  return pos;
}