C++: Wrapping Vector<Char> with Istream

C++: Wrapping vectorchar with istream

You'd define a streambuf subclass wrapping the vector, and pass an instance of that to the istream constructor.

If the data does not change after construction, it is sufficient to set up the data pointers using streambuf::setg(); the default implementation for the other members does the right thing:

template<typename CharT, typename TraitsT = std::char_traits<CharT> >
class vectorwrapbuf : public std::basic_streambuf<CharT, TraitsT> {
public:
vectorwrapbuf(std::vector<CharT> &vec) {
setg(vec.data(), vec.data(), vec.data() + vec.size());
}
};

std::vector<char> data;
// ...
vectorwrapbuf<char> databuf(data)
std::istream is(&databuf);

If you need anything more advanced than that, override the streambuf::underflow method.

Wraps a vectorunsigned char inside a stream?

I think something like this might work

std::vector<unsigned char> data;
std::istringstream stream_in("input message");
std::stringstream stream_out;
functionA(stream_in, stream_out);
const std::string& str_out(stream_out.str());
copy(str_out.begin(), str_out.end(), std::back_inserter(data));
functionB(data);

How to initialise a stringstream from a vector char

The istringstream takes a string, and a string can be made from two char iterators, like this:

istringstream iss(string(v.begin(), v.end()));

Reading from const std::vectorchar via std::istream

I feel quite certain that basic_streambuf requires it's first template to be not-const. Also, I think basic_streambuf requires write access, because the basic_streambuf manages both in and out, regardless of what you use it for in the end. You should probably also override some other members to cause writes to fail: sputbackc, sungetc, sputc, sputn, xsputn...

§ 27.2.2/2 In the classes of Clause 27, a template formal parameter with name charT represents a member of the set of types containing char, wchar_t, and any other implementation-defined character types that satisfy the requirements for a character on which any of the iostream components can be instantiated.

(emphsis mine) This rule is a little vague, but I'm pretty sure it clearly covers your case.

tellg and seekg not working when wrap vectorchar in istream

seekg and tellg ask the streambuf via pubseekoff and pubseekpos to actually perform the work. The default implementation of these functions simply fail.

You need to implement seekoff and seekpos in your streambuf.

How to read specific number of bytes from istream into a vector?

The vector container wraps a dynamic array. It is important to understand the difference between capacity and size of a vector.

Size:
The size of a vector is the number of items it is currently holding.

Capacity:
Capacity is the number of items the vector can hold without requiring a memory reallocation.

The array which the container wraps can be larger than the number of elements it contains. When you push back a new element, the vector will add it to the end of the array. If there is no room left, i.e: capacity was already equal to the size before before pushing, the vector requests for a larger array.

In your code, you have used reserve which is used to increase the capacity of the vector. The size of the vector remains zero.

To increase the size of the vector, you should use resize.

Get an istream from a char*

Here's a non-deprecated method found on the web, has you derive your own std::streambuf class, but easy and seems to work:

#include <iostream>
#include <istream>
#include <streambuf>
#include <string>

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

int main()
{
char buffer[] = "I'm a buffer with embedded nulls\0and line\n feeds";

membuf sbuf(buffer, buffer + sizeof(buffer));
std::istream in(&sbuf);
std::string line;
while (std::getline(in, line)) {
std::cout << "line: " << line << "\n";
}
return 0;
}

Which outputs:

line: I'm a buffer with embedded nullsand line
line: feeds

Inheriting std::istream or equivalent

What you should do is write a streambuf which uses the QDataStream readBytes and writeBytes to implement its functions. Then register the streambuf into a istream with rdbuf (you can also write an istream descendant which does this when initialized).

Boost contains a library aiming at facilitating the writing of streambuf. It could be simpler to use it than understanding the streambuf interface (personally I never have used it but I've written multiple streambuf; I'll see if I've a example that I can post).

Edit: here is something (commented in French -- it comes from the french FAQ of fr.comp.lang.c++ --, I have no time for translation and think it is better to leave them than to remove them) which wraps FILE* call into a streambuf. This also is a show case of a use of private inheritance: ensuring that what could be a member is initialized before a base class. In the case of IOStream, the base class could as well receive a NULL pointer and then the member init() used to set the streambuf.

#include <stdio.h>
#include <assert.h>

#include <iostream>
#include <streambuf>

// streambuf minimal encapsulant un FILE*
// - utilise les tampons de FILE donc n'a pas de tampon interne en
// sortie et a un tampon interne de taille 1 en entree car l'interface
// de streambuf ne permet pas de faire moins;
// - ne permet pas la mise en place d'un tampon
// - une version plus complete devrait permettre d'acceder aux
// informations d'erreur plus precises de FILE* et interfacer aussi
// les autres possibilites de FILE* (entre autres synchroniser les
// sungetc/sputbackc avec la possibilite correspondante de FILE*)

class FILEbuf: public std::streambuf
{
public:

explicit FILEbuf(FILE* cstream);
// cstream doit etre non NULL.

protected:

std::streambuf* setbuf(char_type* s, std::streamsize n);

int_type overflow(int_type c);
int sync();

int_type underflow();

private:

FILE* cstream_;
char inputBuffer_[1];
};

FILEbuf::FILEbuf(FILE* cstream)
: cstream_(cstream)
{
// le constructeur de streambuf equivaut a
// setp(NULL, NULL);
// setg(NULL, NULL, NULL);
assert(cstream != NULL);
}

std::streambuf* FILEbuf::setbuf(char_type* s, std::streamsize n)
{
// ne fait rien, ce qui est autorise. Une version plus complete
// devrait vraissemblablement utiliser setvbuf
return NULL;
}

FILEbuf::int_type FILEbuf::overflow(int_type c)
{
if (traits_type::eq_int_type(c, traits_type::eof())) {
// la norme ne le demande pas exactement, mais si on nous passe eof
// la coutume est de faire la meme chose que sync()
return (sync() == 0
? traits_type::not_eof(c)
: traits_type::eof());
} else {
return ((fputc(c, cstream_) != EOF)
? traits_type::not_eof(c)
: traits_type::eof());
}
}

int FILEbuf::sync()
{
return (fflush(cstream_) == 0
? 0
: -1);
}

FILEbuf::int_type FILEbuf::underflow()
{
// Assurance contre des implementations pas strictement conformes a la
// norme qui guaranti que le test est vrai. Cette guarantie n'existait
// pas dans les IOStream classiques.
if (gptr() == NULL || gptr() >= egptr()) {
int gotted = fgetc(cstream_);
if (gotted == EOF) {
return traits_type::eof();
} else {
*inputBuffer_ = gotted;
setg(inputBuffer_, inputBuffer_, inputBuffer_+1);
return traits_type::to_int_type(*inputBuffer_);
}
} else {
return traits_type::to_int_type(*inputBuffer_);
}
}

// ostream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::ostream

class oFILEstream: private FILEbuf, public std::ostream
{
public:
explicit oFILEstream(FILE* cstream);
};

oFILEstream::oFILEstream(FILE* cstream)
: FILEbuf(cstream), std::ostream(this)
{
}

// istream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::istream

class iFILEstream: private FILEbuf, public std::istream
{
public:
explicit iFILEstream(FILE* cstream);
};

iFILEstream::iFILEstream(FILE* cstream)
: FILEbuf(cstream), std::istream(this)
{
}

// petit programme de test
#include <assert.h>
int main(int argc, char* argv[])
{
FILE* ocstream = fopen("result", "w");
assert (ocstream != NULL);
oFILEstream ocppstream(ocstream);
ocppstream << "Du texte";
fprintf(ocstream, " melange");
fclose(ocstream);
FILE* icstream = fopen("result", "r");
assert (icstream != NULL);
iFILEstream icppstream(icstream);
std::string word1;
std::string word2;
icppstream >> word1;
icppstream >> word2;
char buf[1024];
fgets(buf, 1024, icstream);
std::cout << "Got :" << word1 << ':' << word2 << ':' << buf << '\n';
}


Related Topics



Leave a reply



Submit