7

I have the following implementation based on e.g. this question and answer

struct membuf : std::streambuf
{
  membuf(char* begin, char* end)
  {
    this->setg(begin, begin, end);
  }

protected:
  virtual pos_type seekoff(off_type off,
                           std::ios_base::seekdir dir,
                           std::ios_base::openmode which = std::ios_base::in)
  {
    std::istream::pos_type ret;
    if(dir == std::ios_base::cur)
    {
      this->gbump(off);
    }
    // something is missing here...
  }
};

I would like to use it in my methods in the following way:

  char buffer[] = { 0x01, 0x0a };
  membuf sbuf(buffer, buffer + sizeof(buffer));
  std::istream in(&sbuf);

and then call e.g. tellg() on in and get the correct result.

So far it's almost perfect - it doesn't stop at the end of the stream.

How should I upgrade this so that it works correctly?

My main motivation is to mimic std::ifstream behavior but with binary char[] fed into them in tests (instead of relying on binary files).

Community
  • 1
  • 1
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • What do you mean 'it doesn't stop'? – SergeyA Jan 28 '16 at 16:14
  • @SergeyA Somewhere in my client code I call `in.tellg()` and check whether its less than my desired 'destination' position. This fails and reads one more element in the loop than I would like. – Patryk Jan 28 '16 at 16:16
  • It is still not clear what you mean by 'fails'. Tellg is expected to tell you the current position of the buffer, no more, no less. If you managed to be beyond the buffer limit, tellg will tell you so. – SergeyA Jan 28 '16 at 16:17
  • @SergeyA I think I got it. I add in the commented section `return gptr() - eback();` and now it works :) – Patryk Jan 28 '16 at 16:22

2 Answers2

9

The accepted answer does not work for cases where the seek direction is set to either std::ios_base::beg or std::ios_base::end. To support these cases, extend the implementation by:

pos_type seekoff(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);
  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
5

It seems that I was missing the return with current position. So the final implementation of seekoff looks like:

  pos_type seekoff(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();
  }
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • To person who -1'd : any comment why? – Patryk Nov 09 '18 at 10:25
  • What if `off` pushes the get pointer beyond the beginning or end of the buffer? And what if someone tries to seek to the beginning or end? – rdb Apr 28 '19 at 15:18