Link to home
Start Free TrialLog in
Avatar of prain
prainFlag for United States of America

asked on

How to get the count of a stringstream

I am creating a BINARY string stream that can do both input and output. I want to create a function that would give me the current size in bytes anytime I do an input or/and output when you do a read() or a write().

I have created this small example and I expected the gcount() would do that. But did not.

#include <string>
#include <iostream>
#include <sstream>
 
int main ()
{
  std::stringstream sstr(std::stringstream::in  |  std::stringstream::out | std::stringstream::binary );

  sstr.write("50", sizeof (int));
  std::cout << "Count " << sstr.gcount() << std::endl;   //Expected 4, but I get 0

  char readString[10];
  sstr.read(readString, sizeof (int));;
  std::cout << "Count " << sstr.gcount() << std::endl;  // This is OK.
   return 0;
}

Any ideas how to do that?
Avatar of jkr
jkr
Flag of Germany image

What about 'sstr.str().size()'?
gcount gets the number of characters that were obtained by the last (unformatted) input operation. Doing a write is not an input operation.
Avatar of prain

ASKER

jkr,
Thanks. But what I am expecting is to internal buffer to change when you do a write and a read.

In the following example I am expecting after the two reads, the buffer size() to be 0, because to me read() means "you read out" completely from the buffer.
Seems it's not hapenning in stringstreams. So I was thinking to create my own function to do that.

#include <string>
#include <iostream>
#include <sstream>
 
int main ()
{
  std::stringstream sstr(std::stringstream::in  |  std::stringstream::out | std::stringstream::binary );

  sstr.write("50", sizeof (int));
  std::cout << "Internal Buffer 1 : " << sstr.str().size() << std::endl;

  sstr.write("12.34", sizeof (float));
  std::cout << "Internal Buffer 2 : " << sstr.str().size() << std::endl;

  char readString[10];
  sstr.read(readString, sizeof (int));;
  std::cout << "Internal Buffer 3 : " << sstr.str().size() << std::endl;
//I am expecting the size() to be 4


  sstr.read(readString, sizeof (float));;
  std::cout << "Internal Buffer 4 : " << sstr.str().size() << std::endl;
//I am expecting the size() to be 0

 
  return 0;
}
Hmmm, your assumptions are wrong for one simple reason:

#include <string>
#include <iostream>
#include <sstream>
 
int main ()
{
  std::stringstream sstr(std::stringstream::in  |  std::stringstream::out | std::stringstream::binary );

  sstr.write("50", sizeof (int)); // writes 4 bytes, since 'sizeof(int) == 4'
  std::cout << "Internal Buffer 1 : " << sstr.str().size() << std::endl;

  sstr.write("12.34", sizeof (float)); // writes 4 bytes, since 'sizeof(float) == 4'
  std::cout << "Internal Buffer 2 : " << sstr.str().size() << std::endl;

  char readString[10];
  sstr.read(readString, sizeof (int));; // reads 4 bytes, since 'sizeof(int) == 4'
  std::cout << "Internal Buffer 3 : " << sstr.str().size() << std::endl;
//I am expecting the size() to be 4


  sstr.read(readString, sizeof (float));; // reads 4 bytes, since 'sizeof(int) == 4'
  std::cout << "Internal Buffer 4 : " << sstr.str().size() << std::endl;
//I am expecting the size() to be 0

 
  return 0;
}

Open in new window


But anyway, 'size()' does not seem to work...
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
if you want to write binary data to stringstream do

int i = 50;
ss.write((char*)&i, sizeof(i));

Open in new window


you wouldn't need the binary flag to store binary data cause the binary flag rules only line endings when reading from/writing to files.  

at windows if opening files in text mode a read operation would convert a  CRLF pair in the file  (hex 0x0D 0x0A or '\r' '\n'  in c++) to a single '\n'  in buffer. in a write operation windows would convert '\n' to a CRLF pair in file. as far as i know it has no meaning for stringstream.

stringstream is a typedef of basic_stringstream and is derived from basic_iostream which is derived from both basic_istream and basic_ostream. so actually it is two stream objects though both streams do share a member pointer to basic_streambuf via the common virtual baseclass basic_ios.

              basic_ios
        /                         \
basic_istream     basic_ostream
       \                         /
       basic_iostream
                   |
      basic_stringstream

you could not access the streambuf member of basic_ios directly cause it is a private member, but for my STL the member function rdbuf() would return that pointer.

streambuf has some public member functions like sgetn which returns the count of characters up from a given pointer (pointing into buffer). but all that could be specific to my compiler and its standard library and may not have same implementation at your system.

generally, it seemed easier for me to access the buffer via str() member function as you did. after a write operation the str.size() would show size of the output string buffer. after a read operation (if successful) it should show 0 beside your read operation doesn't read all of the string. so if the ss.str().size() was 10 before read and you read 4 byte, i would expect a rest of 6.

Sara
Avatar of prain

ASKER

It sounds like this is not what I want. But let me tyest out couple of examples and post back here.

BTW, If I use another data structure such as a Queue so something, how would I store "Binary Data". That's for sure is a requirement for us.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
the basic_ostream and basic_istream part are two objects which share a common basic_ios.

the rdbuf is a member function, the streambuf member is a data member. while the first is public, the second is private (at my system) and could not accessed directly. that is exactly what was told.

the sgetn rightly does a copy. it returns streamsize what made me think it returns the current size of the stream buffer. that is not true. it returns the number of character copied.  

for storing binary and text data usually a std::vector<unsigned char> would be a good choice. you could make an own container class which has the vector as a member and some additional 'pointers' into that buffer. that way the class could behave like a stream if that is the goal. if you want to serialize data for exchange in a network you might consider boost library which has excellent solutions for that.

Sara
the istream and ostream both add additional members to the shared streambuf which need to be considered cause those determine the interface to the internal buffer. for example, the basic_istream has a member of type streamsize (_Chcount on my system)  which was commented as "character count" and therefore likely is relevant for the question. also in memory there are at least two separated locations where the 'object' was stored. simplification of a complex multi-inheritance class doesn't help avoiding misunderstandings. my understanding of such an object is a graph where each class involved has its own node.

the comment regarding rdbuf was made parallel to the comment of infinity08. it was not intended to add the same information twice. i added the 'obvious' cause oop principles normally would forbid to expose private members by a public getter. i think the rdbuf was provided to allow classes which use a stream class as member to get access to the internal buffer of that stream.

Sara
Avatar of prain

ASKER

evilrix,
Thanks. Yes, I finally got this working the way I want by warapping a stringstream and then having my own counter within the class. The reason I wanted to use a stringstream is because of it's performance. we have done some performance testing on other data structures such as deques, stacks, lists etc and the results of those containers are no where near how stringstream performs specially on a network application. So it was worth for me to warpup a stringstream and build my own class to do the operations I wanted.

Thanks again all.
prain
Fab. I'm very pleased you found a solution that worked for you. :)