Deriving from StreamBuf - input buffer

  • Thread starter Christopher Pisz
  • Start date
C

Christopher Pisz

I found an article
http://spec.winprog.org/streams/
as a starting point, but it seems to do alot of things that aren't very
standard at all. One particular problem is, that he is using a vector as his
input buffer and trys to assign an iterator to a char pointer.

....
class winzoostreambuffer : private LoggerConsole, public
sts::basic_streambuf<char, std::char_traits<char>>
....
int winzoostreambuffer::uflow()
{
char c;

// GetInput() returns a char from a custom console device
while( c = GetInput() != '\n' )
_inputbuffer.pushback(c);

_inputbuffer.push_back(c);
_Pbeg = pCur =0, _PLength =0;

// compiler complains here about assigning vector<char>::iterator to char
*
_GBeg = _GCur = _inputbuffer.begin(), _GLength =0;

_Init( &_GBeg, &_GCur, &_Glength, &pBeg, &_PCur, &_PLnegth);
}

I don't think I can just static_cast it, can I? How do you go about using a
vector as the underyling buffer?
 
C

Christopher Pisz

Christopher Pisz said:
I found an article
http://spec.winprog.org/streams/
as a starting point, but it seems to do alot of things that aren't very
standard at all. One particular problem is, that he is using a vector as
his input buffer and trys to assign an iterator to a char pointer.

...
class winzoostreambuffer : private LoggerConsole, public
sts::basic_streambuf<char, std::char_traits<char>>
...
int winzoostreambuffer::uflow()
{
char c;

// GetInput() returns a char from a custom console device
while( c = GetInput() != '\n' )
_inputbuffer.pushback(c);

_inputbuffer.push_back(c);
_Pbeg = pCur =0, _PLength =0;

// compiler complains here about assigning vector<char>::iterator to
char *
_GBeg = _GCur = _inputbuffer.begin(), _GLength =0;

_Init( &_GBeg, &_GCur, &_Glength, &pBeg, &_PCur, &_PLnegth);
}

I don't think I can just static_cast it, can I? How do you go about using
a vector as the underyling buffer?


sorry, I should add that

_PBeg, _PCur, _GBeg, and _GCur where all defined as private char * pointers
to the "winzoostreambuffer" class
and _PLength and _GLength are private ints to the class. I thought they were
part of stream buffer, but appear to be some kind of intermediates before
giving them to streambuffer's Init function which takes char * arguments
 
C

Christopher Pisz

Christopher Pisz said:
sorry, I should add that

_PBeg, _PCur, _GBeg, and _GCur where all defined as private char *
pointers to the "winzoostreambuffer" class
and _PLength and _GLength are private ints to the class. I thought they
were part of stream buffer, but appear to be some kind of intermediates
before giving them to streambuffer's Init function which takes char *
arguments

I tryed changing to _GBeg = GCur = &(*(_inputbuffer.begin())), GLen = 0;
and it compiled, but warned about assigning a __w64 int to a int, I guess
because my compiler uses 64 bit pointers.
I also got an assertion when executing the test case, saying, "vector
iterator not dereferenceable"

I also tryed using the addres of front and the address of back+1, but got
the same assertion.

I can only assume that vector does not allocate its elements in consecutive
memory locations and therefore doesn't want me using pointers at all. Is
that correct?
If so, am I not able to use a vector as the buffer for a basic_streambuf?
 
J

James Kanze

I found an articlehttp://spec.winprog.org/streams/ as a
starting point, but it seems to do alot of things that aren't
very standard at all.

And it seems fairly complex for something that is very, very
simple.
One particular problem is, that he is using a vector as his
input buffer and trys to assign an iterator to a char pointer.

Which, of course, doesn't work. You can, however, use &v[0] to
get the address of the first element, and it is guaranteed that
all of the following elements will be contiguous.
...
class winzoostreambuffer : private LoggerConsole, public
sts::basic_streambuf<char, std::char_traits<char>>
...
int winzoostreambuffer::uflow()
{
char c;
// GetInput() returns a char from a custom console device
while( c = GetInput() != '\n' )
_inputbuffer.pushback(c);
_inputbuffer.push_back(c);
_Pbeg = pCur =0, _PLength =0;

// compiler complains here about assigning vector<char>::iterator to char
*
_GBeg = _GCur = _inputbuffer.begin(), _GLength =0;
_Init( &_GBeg, &_GCur, &_Glength, &pBeg, &_PCur, &_PLnegth);
}
I don't think I can just static_cast it, can I? How do you go
about using a vector as the underyling buffer?

The usual way is by using &vect[0] to get the address, and
vect.size() for the length. Be very, very careful not to do
anything later which will invalidate the pointer, however.

FWIW: you don't have to override uflow(). The usual solution
just involves overriding underflow, with something like:

int
MyStreamBuf::underflow()
{
if ( gptr() == egptr() ) {
// Fill buffer...
if ( ! buffer.empty() ) {
setg( &buffer[ 0 ],
&buffer[ 0 ],
&buffer[ 0 ] + buffer.size() ) ;
}
}
return gptr() == egptr()
? EOF
: *gptr() ;
}
 
J

James Kanze

[...]
sorry, I should add that
_PBeg, _PCur, _GBeg, and _GCur where all defined as private char * pointers
to the "winzoostreambuffer" class
and _PLength and _GLength are private ints to the class. I
thought they were part of stream buffer, but appear to be some
kind of intermediates before giving them to streambuffer's
Init function which takes char * arguments

std::streambuf doesn't have an Init() function.
 
J

James Kanze

While I'm at it: although I don't think it's your problem, the
names above result in undefined behavior. You're not allowed to
use names which start with an underscore followed by a capital
letter.
I tryed changing to _GBeg = GCur = &(*(_inputbuffer.begin())),
GLen = 0; and it compiled, but warned about assigning a __w64
int to a int, I guess because my compiler uses 64 bit
pointers.

Or maybe because _GLength is a char* (although you still
shouldn't be getting a warning for that). If _GBeg and GCur are
char*, and _inputbuffer is an std::vector<char>, the above
should be legal, and there's no reason to complain.

For more information (and in general anyway), you should split
up the assignments into separate statements. There is
practically never any reason to use the comma operator (except
obfuscation).
I also got an assertion when executing the test case, saying,
"vector iterator not dereferenceable"

Hmmm. Off hand, that sounds like the vector was empty. If the
vector is empty, begin() returns the same iterator as end(), and
you're not allowed to dereference that.
I also tryed using the addres of front and the address of
back+1, but got the same assertion.

Again, if the array is empty, you're not allowed to call front()
or back().
I can only assume that vector does not allocate its elements
in consecutive memory locations and therefore doesn't want me
using pointers at all. Is that correct?

Of course not. Using set::vector< char > is pretty much
standard practice in a streambuf which requires buffering of an
unknown size.

The normal way of doing this would be:

if ( buffer.empty() ) {
setg( NULL, NULL, NULL ) ;
} else {
setg( &buffer[ 0 ],
&buffer[ 0 ],
&buffer[ 0 ] + buffer.size() ) ;
}

(For an explination of a really simple example of user defined
streambufs, see http://kanze.james.neuf.fr/articles-en.html.)
 
J

James Kanze

(For an explination of a really simple example of user defined
streambufs, seehttp://kanze.james.neuf.fr/articles-en.html.)
Took a look at the site, but the link to the full source code
is broken.

So it is. I'd forgotten that there were links in the articles
when I did some renaming some years back. If you use the link
from the starting page, however, it will work.
 

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,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top