Encapsulation d'un buffer dans un stream

14 réponses
Avatar
Philippe MESMEUR
Bonjour =E0 tous,

je cherche =E0 encapsuler un buffer dans un ostream afin de pouvoir y
acc=E9der de la mani=E8re suivante:



void TestOutStream(ostream & a_oStream)
{
a_oStream << "HELLO" << endl << "WORLD" << endl;
a_oStream << "FOO\nBAR" << endl;
a_oStream << "\001\002\003" << endl;
cout << "=3D> tellp: " << a_oStream.tellp() << endl;
}

const unsigned int SIZE =3D 32;
char buf[SIZE];

ostream.SetBuffer(buf, SIZE); /// voici ce que j'aimerais arriver =E0
faire
TestOutStream(ostream);

cout << buf << endl;



L'=E9criture dans le ostream (ou classe d=E9riv=E9e, bien entendu)
entrainerait une =E9criture dans le buffer buf. Le d=E9bordement serait
=E9galement g=E9r=E9.

Existe-t-il des classes std faisant ce que je viens de d=E9crire?
Comment dois-je m'y prendre?

Merci beaucoup pour votre aide

Philippe

10 réponses

1 2
Avatar
Michael Doubez
On 30 déc, 10:12, Philippe MESMEUR wrote:
Bonjour à tous,

je cherche à encapsuler un buffer dans un ostream afin de pouvoir y
accéder de la manière suivante:

void TestOutStream(ostream & a_oStream)
{
        a_oStream << "HELLO" << endl << "WORLD" << endl;
        a_oStream << "FOOnBAR" << endl;
        a_oStream << "010203" << endl;
        cout << "=> tellp: " << a_oStream.tellp() << endl;

}

const unsigned int SIZE = 32;
char               buf[SIZE];

ostream.SetBuffer(buf, SIZE);  /// voici ce que j'aimerais arriver à
faire
TestOutStream(ostream);

cout << buf << endl;

L'écriture dans le ostream (ou classe dérivée, bien entendu)
entrainerait une écriture dans le buffer buf. Le débordement serait
également géré.

Existe-t-il des classes std faisant ce que je viens de décrire?



Il existe ostringstream mais je suppose que tu veux t'épargner une
copy.

Comment dois-je m'y prendre?



Il est peut être possible d'utiliser un streambuf() nu en utilisant
pubsetbuf() pour positionner le buffer. Je n'ai jamais essayé

Sinon, faire un bufferbuf sur le modèle de stringbuf.
En rapide: hériter de streambuf et redefinir:
- underflow(): lire un char du buffer
- overflow(): écrire un char dans le buffer

--
Michael
Avatar
Philippe MESMEUR
On 30 déc, 12:53, Michael Doubez wrote:
On 30 déc, 10:12, Philippe MESMEUR wrote:




Il est peut être possible d'utiliser un streambuf() nu en utilisant
pubsetbuf() pour positionner lebuffer. Je n'ai jamais essayé




J'avais oublié de le marqué dans mon premier message mais j'ai fais le
test avec pubsetbuf().

const unsigned int SIZE = 32;
char buf[SIZE];

ostringstream testStream(ostringstream::out | ostringstream::in);
testStream.rdbuf()->pubsetbuf(buf, SIZE);


TestOutStream(testStream);

à la sortie, buf n'est absolument pas modifié, et pour cause:

_Myt *pubsetbuf(_Elem *_Buffer, streamsize _Count)
{ // offer _Buffer to external agent
return (setbuf(_Buffer, _Count));
}


virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{ // offer buffer to external agent (do nothing)
return (this);
}

ces deux méthodes sont définie dans la classe basic_streambuf

Sinon, faire un bufferbuf sur le modèle de stringbuf.
En rapide: hériter de streambuf et redefinir:
- underflow(): lire un char dubuffer
- overflow(): écrire un char dans lebuffer

--
Michael


Avatar
Philippe MESMEUR
On 30 déc, 14:22, Philippe MESMEUR wrote:
On 30 déc, 12:53, Michael Doubez wrote:

> On 30 déc, 10:12, Philippe MESMEUR wrote :

> Il est peut être possible d'utiliser un streambuf() nu en utilisant
>pubsetbuf() pour positionner lebuffer. Je n'ai jamais essayé

J'avais oublié de le marqué dans mon premier message mais j'ai fais l e
test avecpubsetbuf().

const unsigned int SIZE = 32;
char               buf[SIZE];

ostringstream testStream(ostringstream::out | ostringstream::in);
testStream.rdbuf()->pubsetbuf(buf, SIZE);

TestOutStream(testStream);

à la sortie, buf n'est absolument pas modifié, et pour cause:

_Myt *pubsetbuf(_Elem *_Buffer, streamsize _Count)
{       // offer _Buffer to external agent
        return (setbuf(_Buffer, _Count));

}

virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
{       // offer buffer to external agent (do nothing)
        return (this);

}

ces deux méthodes sont définie dans la classe basic_streambuf

> Sinon, faire un bufferbuf sur le modèle de stringbuf.
> En rapide: hériter de streambuf et redefinir:
> - underflow(): lire un char dubuffer
> - overflow(): écrire un char dans lebuffer

> --
> Michael



Très surprenant, jusqu'à présent je faisais mes tests sous Visual
Studio 2005 mais il semble que le même code (utilisant la méthode
pubsetbuf()) fonctionne correctement sous Cygwin. Dois-je en déduire
que c'est l'implémentation des stream std de Microsoft qui est..
foireuse?

Philippe
Avatar
Michael Doubez
On 30 déc, 14:30, Philippe MESMEUR wrote:
On 30 déc, 14:22, Philippe MESMEUR wrote:



> On 30 déc, 12:53, Michael Doubez wrote:

> > On 30 déc, 10:12, Philippe MESMEUR wro te:

> > Il est peut être possible d'utiliser un streambuf() nu en utilisant
> >pubsetbuf() pour positionner lebuffer. Je n'ai jamais essayé

> J'avais oublié de le marqué dans mon premier message mais j'ai fais le
> test avecpubsetbuf().

> const unsigned int SIZE = 32;
> char               buf[SIZE];

> ostringstream testStream(ostringstream::out | ostringstream::in);
> testStream.rdbuf()->pubsetbuf(buf, SIZE);

> TestOutStream(testStream);

> à la sortie, buf n'est absolument pas modifié, et pour cause:

> _Myt *pubsetbuf(_Elem *_Buffer, streamsize _Count)
> {       // offer _Buffer to external agent
>         return (setbuf(_Buffer, _Count));

> }

> virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
> {       // offer buffer to external agent (do nothing)
>         return (this);

> }

> ces deux méthodes sont définie dans la classe basic_streambuf

> > Sinon, faire un bufferbuf sur le modèle de stringbuf.
> > En rapide: hériter de streambuf et redefinir:
> > - underflow(): lire un char dubuffer
> > - overflow(): écrire un char dans lebuffer

> > --
> > Michael

Très surprenant, jusqu'à présent je faisais mes tests sous Visual
Studio 2005 mais il semble que le même code (utilisant la méthode
pubsetbuf()) fonctionne correctement sous Cygwin. Dois-je en déduire
que c'est l'implémentation des stream std de Microsoft qui est..
foireuse?



Je parlait d'utiliser un streambuf pas un stringbuf. stringbuf
redefinit setbuf() donc tu as un comportement qui dépends de
l'implémentation et en plus, ton buffer peut être 'vidé' vers la
string.

Je pensais plutôt à:
streambuf sbuf;
sbuf.pubsetbuf(buf,sizeof(buf));
ostream os(sbuf);

os<<"test";

Je ne sais pas comment ostream gère le buffer en cas d'overflow() qui
rate (je suppose que c'est le comportement par défaut d'overflow()).
Tu vas sûrement avoir un flag bad_bit levé.

--
Michael
Avatar
Philippe MESMEUR
> Je parlait d'utiliser un streambuf pas un stringbuf. stringbuf
redefinitsetbuf() donc tu as un comportement qui dépends de
l'implémentation et en plus, ton buffer peut être 'vidé' vers la
string.

Je pensais plutôt à:
streambuf sbuf;
sbuf.pubsetbuf(buf,sizeof(buf));
ostream os(sbuf);

os<<"test";



le problème est que streambuf n'est pas instanciable: "This is an
abstract base class, therefore no objects can be directly instantiated
from it. The standard hierarchy defines two classes derived from this
one that can be used to directly instantiate objects: filebuf and
stringbuf."

A ce que je comprend, je ne peux utiliser que stringbuf ou filebuf
mais filebuf ne me parrait pas adapté.


A la vue de ce que tu me montre, j'ai légerement changé mon code. A la
place de

ostringstream testStream(ostringstream::out | ostringstream::in);
testStream.rdbuf()->pubsetbuf(buf, SIZE);
TestOutStream(testStream);

j'ai écris

stringbuf sbuf;
sbuf.pubsetbuf(buf, SIZE);
ostream os(&sbuf);

Je suis obligé d'écrire stringbuf et pas streambuf car cette dernière
n'est pas instanciable.
Au final, le problème reste le même: ça marche sous Cygwin/G++ et pas
sous Visual Studio 2005, problème toujours dans la fonction
basic_streambuf::setbuf.
(a ce propos, je me dis que même si streambuf était instanciable, elle
réutiliserait également la fonction setbuf de basic_streambuf et donc
aurait le même problème)

Même si le problème s'avère plus délicat que ce que je pensais au
début, merci encore de votre aide.
Philippe
Avatar
Philippe MESMEUR
On 30 déc, 16:06, Philippe MESMEUR wrote:
> Je parlait d'utiliser un streambuf pas un stringbuf. stringbuf
> redefinitsetbuf() donc tu as un comportement qui dépends de
> l'implémentation et en plus, ton buffer peut être 'vidé' vers la
> string.

> Je pensais plutôt à:
> streambuf sbuf;
> sbuf.pubsetbuf(buf,sizeof(buf));
> ostream os(sbuf);

> os<<"test";

le problème est que streambuf n'est pas instanciable: "This is an
abstract base class, therefore no objects can be directly instantiated
from it. The standard hierarchy defines two classes derived from this
one that can be used to directly instantiate objects: filebuf and
stringbuf."

A ce que je comprend, je ne peux utiliser que stringbuf ou filebuf
mais filebuf ne me parrait pas adapté.

A la vue de ce que tu me montre, j'ai légerement changé mon code. A l a
place de

ostringstream testStream(ostringstream::out | ostringstream::in);
testStream.rdbuf()->pubsetbuf(buf, SIZE);
TestOutStream(testStream);

j'ai écris

stringbuf sbuf;
sbuf.pubsetbuf(buf, SIZE);
ostream os(&sbuf);

Je suis obligé d'écrire stringbuf et pas streambuf car cette derniè re
n'est pas instanciable.
Au final, le problème reste le même: ça marche sous Cygwin/G++ et p as
sous Visual Studio 2005, problème toujours dans la fonction
basic_streambuf::setbuf.
(a ce propos, je me dis que même si streambuf était instanciable, ell e
réutiliserait également la fonction setbuf de basic_streambuf et donc
aurait le même problème)

Même si le problème s'avère plus délicat que ce que je pensais au
début, merci encore de votre aide.
Philippe



Je viens de trouver qu'il existe une classe qui fait ce que je veux:
strstream

strstream myStrStream(buf, SIZE);
TestOutStream(myStrStream);

Cependant, elle est indiqué comme étant obsolète!!! et il est
conseillé d'utiliser les classe de définies dans le header sstream.

Quelqu'un sait-il comment faire faire l'équivalent de strstream avec
les classes de sstream?

Merci d'avance pour votre aide
Philippe
Avatar
Michael Doubez
On 30 déc, 17:12, Philippe MESMEUR wrote:
On 30 déc, 16:06, Philippe MESMEUR wrote:



> > Je parlait d'utiliser un streambuf pas un stringbuf. stringbuf
> > redefinitsetbuf() donc tu as un comportement qui dépends de
> > l'implémentation et en plus, ton buffer peut être 'vidé' vers l a
> > string.

> > Je pensais plutôt à:
> > streambuf sbuf;
> > sbuf.pubsetbuf(buf,sizeof(buf));
> > ostream os(sbuf);

> > os<<"test";

> le problème est que streambuf n'est pas instanciable: "This is an
> abstract base class, therefore no objects can be directly instantiated
> from it. The standard hierarchy defines two classes derived from this
> one that can be used to directly instantiate objects: filebuf and
> stringbuf."

> A ce que je comprend, je ne peux utiliser que stringbuf ou filebuf
> mais filebuf ne me parrait pas adapté.

> A la vue de ce que tu me montre, j'ai légerement changé mon code. A la
> place de

> ostringstream testStream(ostringstream::out | ostringstream::in);
> testStream.rdbuf()->pubsetbuf(buf, SIZE);
> TestOutStream(testStream);

> j'ai écris

> stringbuf sbuf;
> sbuf.pubsetbuf(buf, SIZE);
> ostream os(&sbuf);

> Je suis obligé d'écrire stringbuf et pas streambuf car cette derni ère
> n'est pas instanciable.
> Au final, le problème reste le même: ça marche sous Cygwin/G++ et pas
> sous Visual Studio 2005, problème toujours dans la fonction
> basic_streambuf::setbuf.
> (a ce propos, je me dis que même si streambuf était instanciable, e lle
> réutiliserait également la fonction setbuf de basic_streambuf et do nc
> aurait le même problème)

> Même si le problème s'avère plus délicat que ce que je pensais au
> début, merci encore de votre aide.
> Philippe

Je viens de trouver qu'il existe une classe qui fait ce que je veux:
strstream

        strstream myStrStream(buf, SIZE);
        TestOutStream(myStrStream);

Cependant, elle est indiqué comme étant obsolète!!! et il est
conseillé d'utiliser les classe de définies dans le header sstream.

Quelqu'un sait-il comment faire faire l'équivalent de strstream avec
les classes de sstream?



AMHA il vaut mieux que tu définisses ton propre streambuf quitte a
refaire quelque chose comme strstream (qui doit être pré-standard).

--
Michael
Avatar
James Kanze
On 30 Dec, 13:30, Philippe MESMEUR wrote:
On 30 déc, 14:22, Philippe MESMEUR wrote:
> On 30 déc, 12:53, Michael Doubez wrote:



> > On 30 déc, 10:12, Philippe MESMEUR wro te:



> > Il est peut être possible d'utiliser un streambuf() nu en
> > utilisant pubsetbuf() pour positionner lebuffer. Je n'ai
> > jamais essayé



> J'avais oublié de le marqué dans mon premier message mais
> j'ai fais le test avecpubsetbuf().



> const unsigned int SIZE = 32;
> char buf[SIZE];



> ostringstream testStream(ostringstream::out | ostringstream::in);
> testStream.rdbuf()->pubsetbuf(buf, SIZE);



> TestOutStream(testStream);



> à la sortie, buf n'est absolument pas modifié, et pour cause:



> _Myt *pubsetbuf(_Elem *_Buffer, streamsize _Count)
> { // offer _Buffer to external agent
> return (setbuf(_Buffer, _Count));
> }



> virtual _Myt *__CLR_OR_THIS_CALL setbuf(_Elem *, streamsize)
> { // offer buffer to external agent (do nothing)
> return (this);
> }



> ces deux méthodes sont définie dans la classe basic_streambuf



Si mes souvenirs sont bons, c'est ce qu'exige la norme. Mais tu
ne te sers pas de basic_streambuf.

> > Sinon, faire un bufferbuf sur le modèle de stringbuf.
> > En rapide: hériter de streambuf et redefinir:
> > - underflow(): lire un char dubuffer
> > - overflow(): écrire un char dans lebuffer



Très surprenant, jusqu'à présent je faisais mes tests sous
Visual Studio 2005 mais il semble que le même code (utilisant
la méthode pubsetbuf()) fonctionne correctement sous Cygwin.
Dois-je en déduire que c'est l'implémentation des stream std
de Microsoft qui est.. foireuse?



D'abord, il faudrait savoir exactement ce que tu as fais.
L'implémentation a le droit de réfuser un setbuf : selon
l'implémentation, elle le fera dans des cas différents :
-- systèmatiquement dans le cas de stringstreambuf,
-- s'il y a déjà eu des sorties sur le streambuf,
-- si les iostream sont encore couplés avec les FILE*,
et sans doute d'autres aussi.

--
James Kanze
Avatar
James Kanze
On 30 Dec, 14:29, Michael Doubez wrote:
On 30 déc, 14:30, Philippe MESMEUR wrote:
Je pensais plutôt à:
streambuf sbuf;
sbuf.pubsetbuf(buf,sizeof(buf));
ostream os(sbuf);



os<<"test";



Je ne sais pas comment ostream gère le buffer en cas
d'overflow() qui rate (je suppose que c'est le comportement
par défaut d'overflow()).



ostream ne le gère pas. ostream appelle toujours ou sputc ou
sputn pour ses sorties. C'est le streambuf même qui le gère.

Pour garder la trace de ce qui a été sortie, la solution la plus
simple, c'est un streambuf filtrant qui sauve chaque caractère
dans un buffer à lui.

--
James Kanze
Avatar
James Kanze
On 30 Dec, 15:06, Philippe MESMEUR wrote:

[...]
> Je pensais plutôt à:
> streambuf sbuf;
> sbuf.pubsetbuf(buf,sizeof(buf));
> ostream os(sbuf);



> os<<"test";



le problème est que streambuf n'est pas instanciable: "This is
an abstract base class, therefore no objects can be directly
instantiated from it. The standard hierarchy defines two
classes derived from this one that can be used to directly
instantiate objects: filebuf and stringbuf."



La standard en définit deux (en fait trois), mais tu peux en
définir autant que tu veux. C'est assez rare que je n'ai pas de
streambuf maison dans une application.

A ce que je comprend, je ne peux utiliser que stringbuf ou
filebuf mais filebuf ne me parrait pas adapté.



A la vue de ce que tu me montre, j'ai légerement changé mon
code. A la place de



ostringstream testStream(ostringstream::out | ostringstream::in);
testStream.rdbuf()->pubsetbuf(buf, SIZE);
TestOutStream(testStream);



j'ai écris



stringbuf sbuf;
sbuf.pubsetbuf(buf, SIZE);
ostream os(&sbuf);



Je suis obligé d'écrire stringbuf et pas streambuf car cette
dernière n'est pas instanciable.
Au final, le problème reste le même: ça marche sous Cygwin/G++
et pas sous Visual Studio 2005, problème toujours dans la
fonction basic_streambuf::setbuf.



Qui n'est pas ce que tu veux. Tu veux un comportement un peu
spécial de ton streambuf. La façon à l'obtenir, c'est d'écrire
un streambuf qui fait ce que tu veux.

--
James Kanze
1 2