Inheriting ostream and streambuf with xsputn and overflow

I am doing research on creating my own stream and along with that streambuf to handle the buffer for my ostream. Actually, I have most of the work, I can insert (<<) into my stream and get the lines without any problems. I do this by implementing the xsputn virtual function. However, if I inject (<<) a float or int into the stream instead of the xsputn string, it is never called.

I went through the code and I see that the stream calls do_put and then f_put, which ultimately tries to put the float 1 character at a time in the buffer. I can force it to call my implementation of virtual function overflow (int c), if I leave my buffer without a space and thereby get data for float and int.

Now here is the problem, I need to know when the float is done, is placed in the buffer. Or, to put it another way, I need to know when this is the last time the overflow will be called so that the streaming value is transmitted. The reason xsputn works for me is because I get all the value up and its length. Therefore, I can copy it to the buffer, and then call a function that waits for the buffer to fill.

I admit that I am abusing the ostream design in that I need to cache the output and then send it right away for each value entered (<<).

In any case, to be clear, I will repeat what I shoot in a different way. There is a very good chance that I'm just wrong.

I want to use the inherited ostream and streambuf so that I can enter values ​​in it and let it handle my type conversion for me, then I want to pass this information to another object with which I pass the streambuf descriptor to (for?). This object has expensive I / Os, so I don't want to send 1 char data at a time.

Sorry if this is unclear. And thanks for your time.

+6
source share
1 answer

It’s not very clear what you are doing, although it sounds rudely correct. To be sure: all of your ostream handy constructors for creating and installing your streambuf , a destructor and, possibly, an rdbuf to implementation to process buffers of the correct type. Suppose this is true: the definition of xsputn in your streambuf is purely an optimization. The key function that you must define is overflow . The simplest overflow implementation simply takes one character and outputs it to the receiver. Everything except this is optimization: you can, for example, configure the buffer with setp ; if you do this, then overflow will only be called when the buffer is full or flash. In this case you will have to (use pbase and pptr to get the addresses). (The base class streambuf initializes pointers to create a buffer of length 0, so there will be overflow for each character.) Other functions that you might want to override in (very) specific cases:

imbue : If you need a locale for some reason. (Remember that the current character encoding is part of the locale.)

setbuf : For client code to specify a buffer. (IMHO, this is usually not worth the trouble, but you may have special requirements.)

seekoff : Search support. I have never used this in any of my streambuf s, so I cannot give any information other than what you can read in the standard.

sync : called on a flash, should output any characters to the buffer to the shell. If you never call setp (so there is no buffer), you are always in sync, and this may be non-op. overflow or uflow can call this, or both can call some separate function. (The only difference between sync and uflow is that uflow is only called if there is a buffer, and it will never be called if the buffer is empty. sync will be called if the client code flushes the stream.)

When writing my own threads, if performance does not dictate otherwise, I will keep it simple and only override overflow . If performance specifies a buffer, I usually put the code in the dump buffer in a separate write(address, length) function and implement overflow and sync along the lines from:

 int MyStreambuf::overflow( int ch ) { if ( pbase() == NULL ) { // save one char for next overflow: setp( buffer, buffer + bufferSize - 1 ); if ( ch != EOF ) { ch = sputc( ch ); } else { ch = 0; } } else { char* end = pptr(); if ( ch != EOF ) { *end ++ = ch; } if ( write( pbase(), end - pbase() ) == failed ) { ch = EOF; } else if ( ch == EOF ) { ch = 0; } setp( buffer, buffer + bufferSize - 1 ); } return ch; } int sync() { return (pptr() == pbase() || write( pbase(), pptr() - pbase() ) != failed) ? 0 : -1; } 

As a rule, I will not worry about xsputn , but if your client code prints a lot of long lines, this can be useful. Something like this should do the trick:

 streamsize xsputn(char const* p, streamsize n) { streamsize results = 0; if ( pptr() == pbase() || write( pbase(), pptr() - pbase() ) != failed ) { if ( write(p, n) != failed ) { results = n; } } setp( buffer, buffer + bufferSize - 1 ); return results; } 
+13
source

Source: https://habr.com/ru/post/885764/


All Articles