std::streambuf::setp and std::streambuf::epptr()

C

Christopher Pisz

I am trying to empty and reset my internal buffer in my derived sync method.

Am I correct in assuming I can call setp( std::streambuf::pbase(),
std::streambuf::pbase()); to reset the internal buffer?

Also, I am unsure whether the pointer returned by epptr() is supposed to
point just beyond the end of the sequence or at the last element of the
sequence? As such, should the second argument to my setp call be
std::streambuf::pbase() + 1?

Thanks. I've got a book on streams coming for Christmas by the way. Yay!
References on the topic seem to be scarce, yet it is such a huge topic. I
guess most people ignore it as much as they can.
 
H

hsmit.home

I am trying to empty and reset my internal buffer in my derived sync method.

Am I correct in assuming I can call setp( std::streambuf::pbase(),
std::streambuf::pbase()); to reset the internal buffer?
I think your assumption looks correct but shouldn't the 2nd argument
be pbase() + buffer len?
I need to brush up on the STL documentation before I can confirm this.
Also, I am unsure whether the pointer returned by epptr() is supposed to
point just beyond the end of the sequence or at the last element of the
sequence? As such, should the second argument to my setp call be
std::streambuf::pbase() + 1?
Thanks. I've got a book on streams coming for Christmas by the way. Yay!
References on the topic seem to be scarce, yet it is such a huge topic. I
guess most people ignore it as much as they can.
Yes, I've read "C++ Standard Library, The: A Tutorial and Reference"
and they did a reasonable job of explaing all of this. But I want
more!

In case your interested, this is what I managed to conjure up with the
help of the above mentioned reference. It works for me, but is still
under going testing and refinements. I use it as a base class for
tcpip socket and serial comm communication (and encoding).

Code:
//--------------------------------------------------------------
/**
  A generic buffered stream that can be used as the base class
  for hardware / network interfaces such as serial ports, tcpip
  sockets and any device that acts as a I/O stream.

  @ingroup io
  */
class iobuffer : public std::streambuf {

  int                           mLock;
  char *                        mIBuf;
  char *                        mOBuf;
  std::streamsize               mBufSize;

protected:
  //--------------------------------------------------------------
  /**
    Default constructor that provides an abstract base class,
    only inheriting classes may be instantiated.
  */
  iobuffer ()
  : mLock (0)
  , mIBuf(NULL)
  , mOBuf(NULL)
  {
    allocate(8192);
  }

  //--------------------------------------------------------------
  /** destructor */
  virtual ~iobuffer () {
    if (is_locked()) {
      std::cout << "what duh? what should I do now...wait...maybe." <<
std::endl;
    }
    deallocate();
  }

public:
  //--------------------------------------------------------------
  /**
    Returns the number of bytes that may be read from the device.
    If the device is not open or has been closed, a 0 will be
    returned. If a 0 is returned the caller should check whether
    this was due to an invalid device by using the is_open method,
    else the device's receive buffer is empty.

    @todo investigate whether or not to use showmanyc protected
sstream
   */
  virtual std::streamsize       avail () = 0;

  //--------------------------------------------------------------
  /**
    The low-level command that sends the specified binary character
    sequence to the device. A EOF (-1) will be returned if a failure
    occurs, else the number of bytes successfully sent will be
    returned.
    */
  virtual int                   send (const char * s, size_t n) = 0;

  //--------------------------------------------------------------
  /**
    Attempts to receive a maximum number of n characters from the
    device, and copy them into the specified s buffer.
    */
  virtual int                   recv (char * s, size_t n) = 0;

  //--------------------------------------------------------------
  /**
   */
  bool                          is_locked () const {
    return (mLock != 0);
  }

  //--------------------------------------------------------------
  void                          lock () {
    mLock = 1;
  }

  //--------------------------------------------------------------
  void                          unlock () {
    mLock = 0;
  }

  //--------------------------------------------------------------
  void                          deallocate () {
    if (mIBuf) {
      delete[] mIBuf;
    }
    if (mOBuf) {
      delete[] mOBuf;
    }
    mIBuf = NULL;
    mOBuf = NULL;
    mBufSize = 0;
  }

  //--------------------------------------------------------------
  void                          allocate (size_t len) {

    deallocate();

    mBufSize = len;
    // allocate 2 extra characters to enable
    // null terminated unicode padding
    mIBuf = new char[mBufSize+2];
    mOBuf = new char[mBufSize+2];

    setg(mIBuf, mIBuf+mBufSize, mIBuf+mBufSize);
    setp(mOBuf, mOBuf+mBufSize);
    // TODO: throw memory exception in case of failure
  }

protected:
  //--------------------------------------------------------------
  /** pure stream methods */
  //--------------------------------------------------------------

  //--------------------------------------------------------------
  int                           flush () {

    int n = static_cast<int>(pptr() - pbase());

    _send(mOBuf, n);
    pbump(-n);

    return n;
  }

  //--------------------------------------------------------------
  virtual int                   sync () {

    if (flush() == EOF) {
      return -1;
    }
    return 0;
  }

  //--------------------------------------------------------------
  virtual int_type              overflow (int_type c) {

    if (c != EOF) {
      *pptr() = c;
      pbump(1);
    }
    if (flush() == EOF) {
      return EOF;
    }
    return c;
  }

  //--------------------------------------------------------------
  /**

   */
  virtual int_type              underflow () {

    // is read position before end of buffer?
    if (gptr() < egptr()) {
      return *gptr();
    }

    std::streamsize n = avail();
    if (n == 0) {
      return EOF; // no more characters to read
    }

    if (n > mBufSize) {
      n = mBufSize; // if incoming data exceeds buffer size - throttle
it.
    }

    std::streamsize len = _recv(mIBuf, n);

    if (len == -1) {
      return EOF; // ERROR
    }
    if (len == 0) {
      return EOF; // ERROR
    }

    setg(mIBuf, mIBuf, mIBuf+len);
    mIBuf[len] = 0; //null terminate (not really necessary)


    return ((unsigned char)(*gptr()));
  }

  //--------------------------------------------------------------
  /**
    Overrides the base xsgetn method, and enables faster through put
    when reading from the device.
   */
  virtual std::streamsize       xsgetn(char * s, std::streamsize n) {

    std::streamsize len = _recv(mIBuf, n);

    return len;
  }

private:
  //--------------------------------------------------------------
  virtual int                   _send (const char * s, size_t n) {
    return send(s, n);
  }

  //--------------------------------------------------------------
  virtual int                   _recv (char * s, size_t n) {
    return recv(s, n);
  }
};
 
J

James Kanze

I am trying to empty and reset my internal buffer in my
derived sync method.
Am I correct in assuming I can call setp( std::streambuf::pbase(),
std::streambuf::pbase()); to reset the internal buffer?

It depends on what you want to do. If you simply want to clear
the buffer, making sure that the next attempt to write will end
up calling overflow() (where presumably, you'll reinitialize
it), then setting both pointers to NULL is the simplest
solution. If you want to initialize a new (empty) buffer, the
first pointer should be the address of the buffer, and the
second the address one past the end of the buffer.
Also, I am unsure whether the pointer returned by epptr() is
supposed to point just beyond the end of the sequence or at
the last element of the sequence?

One past the end. epptr() - pbase() is the length of the
buffer.
As such, should the second argument to my setp call be
std::streambuf::pbase() + 1?

That would provide a buffer of size 1.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,019
Latest member
RoxannaSta

Latest Threads

Top