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