2

Combining this answer on in-memory streams with this answer on seekoff, I implemented an in-memory buffer as follows:

struct membuf : std::streambuf {
    membuf(char const* base, size_t size) {
        char* p(const_cast<char*>(base));
        this->setg(p, p, p + size);
    }
};
struct imemstream : virtual membuf, std::istream {
    imemstream(char const* base, size_t size) :
        membuf(base, size),
        std::istream(static_cast<std::streambuf*>(this)) {
    }

    std::iostream::pos_type seekoff(std::iostream::off_type off,
                                    std::ios_base::seekdir dir,
                                    std::ios_base::openmode which = std::ios_base::in) {
        if (dir == std::ios_base::cur) gbump(off);
        return gptr() - eback();
    }
};

However, as explained in the comments of the first aswer, we still need to get seekg/seekpos working. So how to correctly implement seekpos here?

PS This question goes in the same direction, but gives a more specific answer.

Community
  • 1
  • 1
Ruben Verborgh
  • 3,545
  • 2
  • 31
  • 43
  • if your stream buffer is a simple memory buffer, then seekpos should simply set the current read-position pointer/index. I see that you don't have those. By default seekg this is a NOP in a basic_streambuf because not all stream buffers support the idea of seeking (imagine a network byte stream). So you'll need to add more code to maintain your own "current read position" and return that from gptr() etc – Richard Hodges Dec 14 '16 at 11:22
  • @RichardHodges _Maintaining_ the position doesn't seem to be a problem: `seekoff` returns the correct result. Rather, I don't know how to _set_ the position. So what I'm looking for is "simply set the current read-position pointer/index" in C++ code. – Ruben Verborgh Dec 14 '16 at 11:40
  • I think you have to implement and maintain these positions in your streambuf-derived class – Richard Hodges Dec 14 '16 at 11:49
  • @RichardHodges The position is definitely maintained already in `gptr()`. It works. It correctly increments and everything. So it is maintained somehow already by the base class. I'm looking for the code to correctly change the `gptr` value. – Ruben Verborgh Dec 14 '16 at 12:05
  • http://en.cppreference.com/w/cpp/io/basic_streambuf/setg – Richard Hodges Dec 14 '16 at 12:22
  • Alright, I've got `setg(eback(), eback() + sp, egptr())` now as body of `seekpos`. Is that all there is to it? – Ruben Verborgh Dec 14 '16 at 12:30
  • I think that's the crux of it. Whether that's *all* there is to it, I doubt. A good place to look would be the source code of the sinks and sources in boost::iostreams, which model std::streambuf. – Richard Hodges Dec 14 '16 at 12:46

1 Answers1

11

Since this hasn't been answered, I'm posting the implementation proposed here.

pos_type seekpos(pos_type sp, std::ios_base::openmode which) override {
  return seekoff(sp - pos_type(off_type(0)), std::ios_base::beg, which);
}

Also, the implementation of seekoff did not work for me in the case of other directions. Consider amending it by the following:

pos_type seekoff(off_type off,
                 std::ios_base::seekdir dir,
                 std::ios_base::openmode which = std::ios_base::in) override {
  if (dir == std::ios_base::cur)
    gbump(off);
  else if (dir == std::ios_base::end)
    setg(eback(), egptr() + off, egptr());
  else if (dir == std::ios_base::beg)
    setg(eback(), eback() + off, egptr());
  return gptr() - eback();
}
Jan Michael Auer
  • 711
  • 9
  • 16