C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Re: norme : basic_stringbuf str(), et pptr() ..

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French)
View previous topic :: View next topic  
Author Message
kanze@gabi-soft.fr
Guest





PostPosted: Mon Sep 08, 2003 10:11 am    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote



Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote


Quote:
je trouve embêtant que la fonction membre basic_stringbuf::str()
renvoie la séquence entière [pbase(), epptr()[
alors que je voudrais parfois [pbase(), pptr() [

Je ne crois pas que la norme est très claire sur ce point. Moi-même,
j'aurais plutôt tendance à l'interpréter dans la façon que tu veux.
(Selon la norme, basic_stringbuf::str() renvoie la « séquence » de
sortie. Sans donner une définition de cette séquence pour un stringbuf.
Et les définitions dans §27.5.1 sont assez vague, exprès pour supporter
des types dérivés différents.)

Quote:
Rappel sur les streambuf

pbase() est le "begin" de la "put area", epptr() le end, et pptr() le
pointeur de la position courante de sorte que si l'on fait :

outstringstream oss;
oss << "abcdefghijkl";
oss.pubseekpos(0, std::ios_base::out);
oss << "ABCD";
[pbase(), pptr() [ contient "ABCD
mais
[pbase(), epptr()[ contient "ABCDefghijkl"

En fait, je ne crois pas que ce dernier est garantie.

Quote:
/Rappel sur les streambuf

Comme pptr() (et ses acolytes) sont protected et qu'un streambuf n'est
pas copiable, il n'y a pas moyen d'accèder à ces pointeurs proprement,
donc pas moyen d'obtenir la sous-chaîne [pbase(), pptr() [

Mais si. On peut dériver.

Quote:
Je trouve ça dommage, car ça empêche de réutiliser un stringstream
sans réallocation.

En détails : il s'avère que la création d'un stringstream est très
lent. (sur g++ en tout cas). même bcp plus lent que la simple
allocation du buffer qu'il contient.

Alors, il y aurait un problème d'implémentation. Malheureusement, je
crois que c'est assez généralement le cas. Je ne sais pas pourquoi.

Quote:
pour une fonction qui fait des formattages répétés, il est intéressant
de réutiliser un stringstream, dans le genre de :

ostringstream oss;
vector {
empty_buffer(oss);
state_restoring tmp(oss);
oss << "bla bla " << hex << 18 << endl;
v.push_back(oss.str());
}
{
empty_buffer(oss);
state_restoring tmp(oss);
oss << "oh, et aussi bla bla, ce coup-ci en décimal " << 77 << endl;
v.push_back(oss.str());
}
// etc..

Tu n'es pas le premier à le vouloir. Jusqu'ici, la réponse a toujours
été que si tu veux un nouveau ostringstream objet, la meilleur façon à
l'obtenir, c'est d'en créer un nouveau. Parce que la réinitialisation de
l'état est loin d'être trivial ; dans le cas général, on ne peut même
jamais être certain que c'est complet.

Maintenant, on peut bien imaginer qu'il y a des cas où on ne veut pas
changer les paramètres de formattage ; où c'est même un avantage de ne
pas avoir à les répositionner à chaque coup.

Quote:
Et ya guère d'autre moyen de définir empty_buffer(..) que par :
void empty_buffer(std::ostringstream& oss) {
oss.str("");
}

qui a l'inconvénient majeur de *désallouer* le buffer courant et d'en
réallouer un nouveau, vide.

J'aimerais bcp mieux pouvoir faire :
void empty_buffer(std::ostringstream& oss) {
oss.rdbuf()->pubseekpos(0, std::ios_base::out);
}

mais alors oss.str() renvoit une copie du buffer alloué entier, alors
que je voudrais seulement [pbase(), pptr()[, mais que je n'ai pas
moyen de l'obtenir..

à cause de ça, je dois définir mon propre streambuf fournissant la
séquence voulue (d'ailleurs, serait-il correct de dériver de stringbuf
en ajoutant juste des méthodes public pour accèder à [pbase(),
pptr()[, ou ça poserait problème ?)

Pourquoi pas simplement dériver de stringbuf, en ajoutant une fonction
truncatedString, qui renvoie ce que tu veux ?

Quote:
[ et il faut définir un stream aussi, tout con mais avec un rdbuf() du
bon type qui permette d'accèder aux fonctions ajoutées ]

Certes.

Quote:
ça serait pas mieux si std::stringbuf permettait ça à la base ?? je
vois des avantages et pas d'inconvénients..

À vrai dire, ce qui me gène la plus, c'est que ce n'est pas bien défini
ce qui se passe dans ce cas-ci. La deuxième chose qui me gène, c'est
qu'effectivement, les implémentations des streambuf sont horriblement
lentes.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Back to top
Samuel Krempp
Guest





PostPosted: Mon Sep 08, 2003 1:06 pm    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote



le Lundi 8 Septembre 2003 12:11, [email]kanze (AT) gabi-soft (DOT) fr[/email] écrivit :

Quote:
Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote in message
news:<3f5bfd70$0$27038$626a54ce (AT) news (DOT) free.fr>...

je trouve embêtant que la fonction membre basic_stringbuf::str()
renvoie la séquence entière [pbase(), epptr()[
alors que je voudrais parfois [pbase(), pptr() [

Je ne crois pas que la norme est très claire sur ce point. Moi-même,
j'aurais plutôt tendance à l'interpréter dans la façon que tu veux.
(Selon la norme, basic_stringbuf::str() renvoie la « séquence » de
sortie. Sans donner une définition de cette séquence pour un stringbuf.

en VO elle dit qu'elle renvoie une copie de 'the basic_stringbuf's
underlying character sequence', qui est dite égale dans le cas de mode
ios_base::out à 'the output sequence'.

si on comprend par là qu'il s'agit de la 'controlled output sequence' dont
il est question au §27.5.1 :

Quote:
Et les définitions dans §27.5.1 sont assez vague, exprès pour supporter
des types dérivés différents.)

oui mais elles disent bien que ces séquences sont caractérisée par 3
pointeurs dans un array object (qui s'étend de xbeg à xend, avec xnext qque
part au milieu), qui représente à tout moment 'a (sub) sequence of
characters from the sequence'.

Donc 'the sequence' contient (au moins) l'intervalle [xbeg, xend[.
ie [pbase(), epptr()[ dans notre cas.

Peut être on peut tout de même l'intérpreter comme il faudrait en
considérant que 'the output sequence' n'est que le morceau [pbase(), pptr(
[ de 'the controlled output sequence', mais vu les dénominations c'est un
peu tordu..


Une autre chose dont je suis pas sûr, c'est si ostringstream::str() peut
retourner une copie d'un string (avec éventuellement copy-on-write), ou
doit vraiment copier chaque élément de la séquence..

Quote:
Rappel sur les streambuf

pbase() est le "begin" de la "put area", epptr() le end, et pptr() le
pointeur de la position courante de sorte que si l'on fait :

outstringstream oss;
oss << "abcdefghijkl";
oss.pubseekpos(0, std::ios_base::out);
oss << "ABCD";
[pbase(), pptr() [ contient "ABCD
mais
[pbase(), epptr()[ contient "ABCDefghijkl"

En fait, je ne crois pas que ce dernier est garantie.

/Rappel sur les streambuf

Comme pptr() (et ses acolytes) sont protected et qu'un streambuf n'est
pas copiable, il n'y a pas moyen d'accèder à ces pointeurs proprement,
donc pas moyen d'obtenir la sous-chaîne [pbase(), pptr() [

Mais si. On peut dériver.

oui c'est vrai, ya moyen d'ajouter ce qu'on veut, par exple

template
class basic_outsstream : private std::basic_stringbuf<Elem, Tr>,
public std::basic_ostream<Elem, Tr>
{
typedef std::basic_string<Elem,Tr> string_t;
public:
basic_outsstream() : std::basic_stringbuf<Elem,Tr>(),
std::basic_ostream<Elem,Tr>(this) {}

// ! physically copy chars
string_t cur_str() const { return string_t(begin(), cur()); }

// copy-less access :
int cur_size() const { return (cur()-begin()); }
const Elem * begin() const { return pbase(); }
const Elem * cur() const { return pptr(); }
const Elem * end() const { return epptr(); }

void empty_buffer() {
typedef typename Tr::pos_type pos_type;
pos_type p = seekpos(0, std::ios_base::out);
assert( p != pos_type(std::streamoff(-1)) );
}
};

typedef basic_outsstream<char> outsstream;


Quote:
Tu n'es pas le premier à le vouloir. Jusqu'ici, la réponse a toujours
été que si tu veux un nouveau ostringstream objet, la meilleur façon à
l'obtenir, c'est d'en créer un nouveau. Parce que la réinitialisation de
l'état est loin d'être trivial ; dans le cas général, on ne peut même
jamais être certain que c'est complet.

du fait de ce qui peut être ajouté à l'état du stream par xalloc(), dans les
tableaux accessibles par iword() et pword() ?

je considère que si qqun y met de l'état supplémentaire, on peut lui laisser
le gèrer sans y toucher. c'est ce que j'ai décidé dans boost::format..
en fait je n'ai pas encore vu d'objet dont le formattage utilise des
paramètres supplémentaires.
alors je m'autorise à supposer que ces formattages se comportent comme une
modification temporaire de l'état, qui est réinitialisé après utilisation.
par exple, imaginons qu'on ajoute de l'état pour rélger des détails de
formattage d'une classe MyComplex :

ostream& operator<<(ostream& os, MyComplex const& z) {
infos = get_some_extra_params_from_stream(os);
os << infos.prefix() << z.real << infos.sep() << z.imag
<< infos.suffix();
return os;
}

( pour être plus utile on pourrait gèrer os.width() en répartissant le
padding sur les 2 composantes, mais bon l'exemple est juste là pour se
fixer les idées. )

les params supplémentaires éventuellement présent dans os (que la fonction
get_some_extra... cherche et renvoi) permettent d'adapter l'apparence du
nbre complexe selon les cas, pour les appelants qui auraient conscience de
ces paramètres supplémentaires (sinon utilise des reglages par défaut)

par exemple, ces paramètres pourront être utilisée qd on veut afficher une
séquence de MyComplex d'une façon différente du défaut :

ostream& operator<<(ostream& os, MyMatrix const& m) {
extra_params_restoring tmp(os);
set_my_extra_params_in_stream(os, " " , "+" , " " );
// prefix=" ", sep="+" et suffix=" "..
for(int i=0; i < m.nblines(); ++i) {
os << "(";
for(int j=0; j < m.nbcolumns(); ++j) {
if(j>0) os << " ";
os << m[i][j];
}
os << ")"
}
// la destruction de tmp restore les paramètres supplémentaires que
// l'on a modifié.
return os;
}

(ce serait évidemment mieux d'aligner les éléments de la matrice en reglant
os.width(..) à chaque élément - et en tronquant si besoin. ou alors en
mesurant d'abord la largeur maxi des éléments ou en reglant le formattage
pour que la largeur des nombres soit toujours bornée..)

bref, j'ai l'impression que dans des utilisations propres d'état
supplémentaire, il est réinitialisé comme il faut tout seul et on ne
devrait pas avoir à s'en soucier qd on réutilise un stream pour formater
des objets inconnus.
il suffit de penser à toujours remettre les paramètres à leur valeurs défaut
après utilisation. Y-a-t-il des exemples où celà ne serait pas possible ?

et je pense qu'il est légitime de réutiliser un stringstream sans se soucier
de possibles états dont on n'a pas conscience.

de toute façon, il suffit que j'ajoute dans la doc de boost::format le
pré-requis que le code appelé par le formattage des objets ne doit pas
modifier des paramètres supplémentaires du stream sans les restaurer à la
fin du formattage.
(pis même tout l'état du stream à la limite, mais c moins nécessaire..)

Comme ça boost::format a officiellement le droit de réutiliser son
stringstream interne Smile
faudrait juste que je trouve une façon d'exprimer ce pré-requis
correctement..

--
Sam

Back to top
Samuel Krempp
Guest





PostPosted: Mon Sep 08, 2003 1:29 pm    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote



le Lundi 8 Septembre 2003 15:20, [email]krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr[/email]
écrivit :

Quote:
mais je trouve qd même que stringstream devrait permettre d'accèder aussi
à ce bout de la chaîne..

et puis, il est parfois dit que strstream est deprecated.

ah oui pis en fait surtout strstream n'est pas un template sur le typye de
caractère, il ne s'occuppe que de char.
c'est pas utilisable si on veut supporter des wchar ou autre..

--
Sam

Back to top
Samuel Krempp
Guest





PostPosted: Sun Sep 14, 2003 9:19 pm    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote

le Tuesday 09 September 2003 11:38, [email]kanze (AT) gabi-soft (DOT) fr[/email] écrivit :

Quote:
Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote in message
Et les définitions dans §27.5.1 sont assez vague, exprès pour supporter
des types dérivés différents.)

oui mais elles disent bien que ces séquences sont caractérisée par 3
pointeurs dans un array object (qui s'étend de xbeg à xend, avec xnext
qque part au milieu), qui représente à tout moment 'a (sub) sequence
of characters from the sequence'.

Oui, mais elle ne dit pas quels « caractères » dans ce tableau font
partie de la séquence, et lesquels non. C'est évident que dans certains,
les caractères derrière xnext n'en font pas partie -- considère le cas
de filebuf, par exemple, ou même stringbuf, dans le cas où on n'a pas
fait un seek.

j'ai vérifié pour précisions, et j'ai découvert avec stupeur que tout
ostringstream doit réallouer son array object à chaque caractère envoyé.
J'ai essayé de trouver où j'avais mal lu la norme, n'étant pas
particulièrement un expert de littérature normative, mais bon je vois pas
où je suis trompé.. Donc voilà la collection de faits de la norme qui m'a
mené à ça :



INTRO
Bref résumé de §27.5.1 qui donne en une page le contexte général des
streambuf.

un streambuf a :
une input sequence
une output ''
qui sont la destination finale des characters manipulé, et qui peut varier
d'un buf à l'autre.
Dans un souci de non-duplication des spécification, la norme parlede 'the
underlying sequence' ou 'the sequence' pour faire référence à une de ces 2
séquences, la spécifiant qd il s'agit de l'output et quand de l'input.

chaque séquence est caractérisée par 3 pointeurs qui pointent dans un
'character array' qui s'étend du pointeur xbeg à xend en passant par xnext
(dont les appels à pbase(), pptr(), epptr() (pour l'output) et gback(),
gptr(), egptr() (pour l'input) donnent les valeurs)

dans le cas général, on sait juste que cet array est une 'sous-séquence' des
séquences controllées.
§27.5.1.2 :
The array object represents, at any moment, a (sub)sequence of characters
from the sequence.
C'est cette phrase, tout à fait sans équivoque, qui à mon avis est très mal
choisie, puisque ça fait que les caracs dans ]xnext, xend[ font partie de
la sequence controlée, et vu que tout se réfère à cette mystérieuse
'séquence controlée', finit en catastrophe.

cette formulation n'est pas intuitive, comme tu dis :

Quote:
Une chose me semble assez claire, pas des mots dans la norme, mais de la
pratique existante, c'est que si j'ouvre un fichier vide, et que j'y
écris une dizaine d'octets, la différence epptr() - pbase() peut bien
être plus que le nombre d'octets dans le fichier, et que du coup, les
octets entre pptr() et epptr() ne font pas partie de la séquence.

le filebuf, c'est le cas typique de buffer, et c'est une image utile pour se
rerprésenter les choses
pourtant la phrase de 27.5.1.2 est sans équivoque, tout ce qui est entre
xbeg et xend fait partie de la séquence controlée. même des chars
non-initialisés dans le fond du buffer..
mais ça veut pas dire pour autant que tous les characters de la sequence
sont des caracs qui vont être envoyés dans le fichier *physique*.
j'ai pas vue ce que dit la norme pour les filebuf, mais rien n'empêche de
définir l'effet physique pour la 'séquence' dont il est question soit la
séquence finale *plus* le bout qui reste du buffer.

(je me concentre sur l'output, parceque j'ai pas pris la peine de lire
sgetc(..) et underflow(..), et tout ce qui concerne la get area, j'en ai
pas l'utilité)


Mais en tout cas, du coup ça rend la définition du stringbuf un peu
merdique, car

§27.7.1.3.5 :
int_type overflow(int_type c = traits::eof());

If traits::eq_int_type( c,traits::eof()) returns false and if either the
output sequence has a write position available or the function makes a
write position available (as described below), the function calls
sputc( c).
[..]
Notes: The function can make a write position available only if ( mode &
ios_base::out) != 0. To make a write position available, the function
reallocates (or initially allocates) an array object with a sufficient
number of elements to hold the current array object (if any), plus one
additional write position. If ( mode & ios_base::in) != 0, the function
alters the read end pointer egptr() to point just past the new write
position (as does the write end pointer epptr()).

[
rappel de 27.5.1 .3 :
If xnext is not a null pointer and xnext < xend for an output sequence, then
a write position is available. In this case, * xnext shall be assignable as
the next element to write (to put, or to store a character value, into the
sequence).
]


Problème :
je trouve pas de moyen d'affirmer que 'la séquence' ne doit pas contenir
plus que les caractères envoyés dans le stringbuf, mais si c'est le cas ce
serait embêtant (car str() retourne une copie de 'la séquence', et je sais
pas qui voudrait avoir n'importe quoi ajouté à ses string)

Donc ajoutons l'axiome
Ax1 : la séquence ne contient rien d'autre que les caractères envoyés vers
le buffer pour 'output', au moins à tout moment où l'on pourrait appeler
son membre str().
(ce que j'appelle "envoyé dans le buffer", c'est ce qu'on a passé au buffer
par des appels à sputc(..) (qui appelle overflow(..) quand il n'y a pas de
'write position' disponible),
ou sputn(..) (qui doit avoir le meme effet que des appels répétés à sputc)


Avec Ax1 et le phrase problèmatique "(sub)sequence" de 27.5.2, chaque appel
à overflow ne peut alors réaliser un agrandissement de plus de 1 caractère
de l'array object, vu qu'aussitôt tout l'array alloué est une sous-séquence
de 'la séquence'.
En effet :
si ya juste un caractère ajouté par overflow, c bon car il appelle ensuite
sputc(..) qui va y mettre le caractère envoyé, l'axiome reste vérifié.
Si le tableau contient 2 ou + nouveaux caractères, un seul sera assigné par
l'appel à sputc, et ensuite 'la sequence' contiendra 1 ou + caractères non
désirés. et là le contrôle peut être rendu au programme qui peut appeler
str(), et Ax1 est violé.


Je ne vois pas l'ombre d'une faille dans le raisonnement, mais je n'attends
que que l'on me prouve le contraire !

Alors je ne sais pas si la phrase fatidique
§27.5.1.2 :
The array object represents, at any moment, a (sub)sequence of characters
from the sequence.

entraîne les mêmes conséquences dans les spécifications de filebuf et autres
buffers, mais en tout cas pour un stringbuf cette phrase est
catastrophique, il faudrait la changer pour dire seulement que le morceau
[xbeg, xnext[ de cet array est une sous-séquence etc...
Ca rend plus intuitif ce qui est désigné par 'la séquence', ça permet à un
stringbuf d'être vraiment bufferisé, et en plus ça ferait que
stringbuf::str() renverrait [xbeg, xnext[, et donc qu'on pourrait utilisé
seekpos(..), qui regle xnext, pour vider son contenu.

ou bien alors ma notion de "(sub)sequence" n'est pas celle de la norme ?

Quote:
Qu'en penses-tu ? Est-ce qu'il y a quelque chose que j'ai mal vu ?

maintenant c'est moi qui pose la même question :)

--
Sam

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Mon Sep 15, 2003 10:50 am    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote

Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote

Quote:
le Tuesday 09 September 2003 11:38, [email]kanze (AT) gabi-soft (DOT) fr[/email] écrivit :
Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote in
message
Et les définitions dans §27.5.1 sont assez vague, exprès pour
supporter des types dérivés différents.)

oui mais elles disent bien que ces séquences sont caractérisée par
3 pointeurs dans un array object (qui s'étend de xbeg à xend, avec
xnext qque part au milieu), qui représente à tout moment 'a (sub)
sequence of characters from the sequence'.

Oui, mais elle ne dit pas quels « caractères » dans ce tableau font
partie de la séquence, et lesquels non. C'est évident que dans
certains, les caractères derrière xnext n'en font pas partie --
considère le cas de filebuf, par exemple, ou même stringbuf, dans le
cas où on n'a pas fait un seek.

j'ai vérifié pour précisions, et j'ai découvert avec stupeur que tout
ostringstream doit réallouer son array object à chaque caractère
envoyé. J'ai essayé de trouver où j'avais mal lu la norme, n'étant pas
particulièrement un expert de littérature normative, mais bon je vois
pas où je suis trompé.. Donc voilà la collection de faits de la norme
qui m'a mené à ça :

Je crains que tu as raison (et que la même chose vaut pour filebuf, et
al.).

Mais il ne faut pas perdre de vue que, normatif ou non, le texte a été
écrit des êtres humains, donc faillibles, et qu'il peut y avoir une
erreur dans l'expression -- que les mots ne disent pas vraiment ce qu'on
voulait qu'ils disent.

[...]
Quote:
§27.5.1.2 :
The array object represents, at any moment, a (sub)sequence of
characters from the sequence.

Cette phrase m'avait échappée quand j'ai lu la norme. (Il ne faut pas
oublier que ma lecture est conditionnée par une expérience importante,
surtout dans les iostream. Dans ce cas-ci, je sais, ou je crois savoir,
ce qu'on voulait dire. C'est donc ce que je lis.)

Quote:
C'est cette phrase, tout à fait sans équivoque, qui à mon avis est
très mal choisie, puisque ça fait que les caracs dans ]xnext, xend[
font partie de la sequence controlée, et vu que tout se réfère à cette
mystérieuse 'séquence controlée', finit en catastrophe.

En effet, je ne vois pas comment on pourrait l'interpréter autrement.
Interprétation qui amène infailliblement à ta conclusion : il faut
réallouer à chaque caractère (ou d'une façon plus générale, dans un flux
de sortie où on n'a jamais fait un seek, et qui était vide au départ,
gptr() == egptr(), toujours.

Éventuellement, dans un streambuf particulier, on pourrait faire jouer
la règle « as if ». À condition, évidemment, qu'il soit impossible à
dériver de la classe, parce que dès qu'on dérive, gptr() et egptr()
deviennent partie de l'interface accessible.

Quote:
cette formulation n'est pas intuitive, comme tu dis :

Une chose me semble assez claire, pas des mots dans la norme, mais
de la pratique existante, c'est que si j'ouvre un fichier vide, et
que j'y écris une dizaine d'octets, la différence epptr() - pbase()
peut bien être plus que le nombre d'octets dans le fichier, et que
du coup, les octets entre pptr() et epptr() ne font pas partie de la
séquence.

le filebuf, c'est le cas typique de buffer, et c'est une image utile
pour se rerprésenter les choses pourtant la phrase de 27.5.1.2 est
sans équivoque, tout ce qui est entre xbeg et xend fait partie de la
séquence controlée. même des chars non-initialisés dans le fond du
buffer..

mais ça veut pas dire pour autant que tous les characters de la
sequence sont des caracs qui vont être envoyés dans le fichier
*physique*.

Ça veut dire qu'ils font partie de la séquence.

En revanche, la description de « overflow » dans §27.8.1.4/8 est assez
claire et détaillée. On commence par la conversion de la séquence
[pbase()..pptr()[, et c'est le résultat de cette conversion qui est
envoyé au système. (Il y a des ambiguïtés en ce qui concerne les
modalités de la conversion, je crois, mais c'est tout à fait clair
qu'elle ne concerne que l'interval ci-dessus.

Ce qui fait poser la question : ça veut dire quoi, alors, faire partie
de la séquence ?

Quote:
j'ai pas vue ce que dit la norme pour les filebuf, mais rien n'empêche
de définir l'effet physique pour la 'séquence' dont il est question
soit la séquence finale *plus* le bout qui reste du buffer.

Le cas de filebuf est assez compliqué à cause de l'utilisation des
codecvt. En revanche, pour cette raison, ils ont dû le décrire en plus
de détail.

Quote:
(je me concentre sur l'output, parceque j'ai pas pris la peine de lire
sgetc(..) et underflow(..), et tout ce qui concerne la get area, j'en
ai pas l'utilité)

Mais en tout cas, du coup ça rend la définition du stringbuf un peu
merdique, car
[...]
Je ne vois pas l'ombre d'une faille dans le raisonnement, mais je
n'attends que que l'on me prouve le contraire !

Malheureusement, j'ai l'impression que tu as raison.

Quote:
Alors je ne sais pas si la phrase fatidique
§27.5.1.2 :
The array object represents, at any moment, a (sub)sequence of
characters from the sequence.

entraîne les mêmes conséquences dans les spécifications de filebuf et
autres buffers, mais en tout cas pour un stringbuf cette phrase est
catastrophique, il faudrait la changer pour dire seulement que le
morceau [xbeg, xnext[ de cet array est une sous-séquence etc...

Changement qui n'est pas pour me déplaire, mais je ne sais pas si c'est
ce qui a été voulu dans le cas où il y a eu des seek. Dans le cas d'un
filebuf, c'est assez évident ce qu'on veut avoir comme « controlled
sequence » (au moins en locale "C") : un seek n'écrase pas de caractères
que si la périphérique les perdent aussi. (Mais je me démande combien
d'implémentations ont réelement le code spécial nécessaire pour traiter
une bande magnétique correctement.) Dans le cas d'un stringstream, on a
deux modèles : un fichier disque (où un seek en arrière, suivi d'une
écriture, n'efface rien) ou une bande magnétique (où chaque écriture
crée une fin de fichier à sa suite).

À mon avis, donc, la solution est plus complexe. Pour commencer, il
faudrait bien dire que la séquence ne comporte pas forcément tous les
caractères du tableau. En suite, qu'on définit précisement ce que c'est
une séquence dans chaqu'une des classes dérivées.

Quote:
Ca rend plus intuitif ce qui est désigné par 'la séquence', ça permet
à un stringbuf d'être vraiment bufferisé, et en plus ça ferait que
stringbuf::str() renverrait [xbeg, xnext[, et donc qu'on pourrait
utilisé seekpos(..), qui regle xnext, pour vider son contenu.

Comme j'ai dit, c'est un peu la solution que je préfère. Mais je ne sais
pas si elle trouve l'unanimité. Parce qu'elle donne à stringbuf un
comportement qui est bien différent que celui de filebuf (dans le cas
classique où il est attaché à un fichier disque).

Je crois en tout cas qu'il faut soulever la question dans comp.std.c++.

Quote:
ou bien alors ma notion de "(sub)sequence" n'est pas celle de la norme ?

Qu'en penses-tu ? Est-ce qu'il y a quelque chose que j'ai mal vu ?

maintenant c'est moi qui pose la même question Smile

Je commence à croire qu'on a réelement à faire à un defaut dans la
norme.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Mon Sep 15, 2003 11:00 am    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote

Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote

Quote:
le Sunday 14 September 2003 23:19,
[email]krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr[/email] écrivit :

§27.7.1.3.5 :
[..]
Notes: The function can make a write position available only if (
mode & ios_base::out) != 0. To make a write position available, the
function reallocates (or initially allocates) an array object with a
sufficient number of elements to hold the current array object (if
any), plus one additional write position. If ( mode & ios_base::in)
!= 0, the function alters the read end pointer egptr() to point just
past the new write position (as does the write end pointer epptr()).

je crois avoir compris : la norme dit bien qu'après chaque appel à
sputc(.) il n'y a pas de 'write position available', et effectivement
à chaque fois il y a réallocation du tableau.

Où est-ce que la norme dit ça ? Si après un appel à sputc, il n'y a plus
de « write position available », il faudrait que le prochain appel à
sputc appelle « overflow ». Où est l'intérêt d'avoir sputc et al. s'il
faut appeler overflow à chaque coup.

Quote:
[ le 'sufficient number of elements' est en fait forcément N+1, N
étant le nombre précédent, et c'est en plus confirmé par ce qui est
dit entre parenthèse à la fin : epptr() pointe sur N+1 +1, or epptr()
correspond à ce qui est appelé xend au 27.5.1: "the end pointer, or
first element address beyond the end of the array (called xendhere)" ]

mais j'ai dû me méprendre sur ce qu'entend la norme par
'réallocation', et en fait une implémentation peut bien réallouer un
gros bloc de mémoire, et y 'mettre' le array object. Puis, les fois
suivantes, la 'réallocation' consistera juste à prendre un caractère
du rabe, l'affecter au tableau, et ne rien déplacer.

C'est une possibilité. Je ne crois pas que ce soit comme ça que les
implémentations courantes fonctionnent (mais je peux me tromper -- elles
ont bien un pointeur supplémentaire quelque part).

Quote:
il n'y a pas forcément copie lors de réallocation, voilà tout.

C'est ça ?

Mais c'est tout de même incroyablement vicieux de formuler les choses
de cette façon. et d'écire :
"with a sufficient number of elements to hold the current array object (if
any), plus one"
(qui laisser croire que c'est dans l'array lui même qu'est la mémoire
réservée en avance, et donc qu'il y a des caractères indésirés dans ]xnext,
xend[)
plutôt que
"with one more element than the current array has"

Je croirais plutôt à un problème de formulation de ce qui est voulu.

Ce qu'il faut voir aussi, c'est que si le seek n'efface pas ce qui suit,
il faut bien quatre pointeurs, à la place de trois. Dans le cas de
filebuf, ça marche parce que le système d'exploitation maintient le
pointeur supplémentaire (à la fin de fichier). Dans le cas de stringbuf,
si on veut que le seek n'efface pas (ce qui est quand même le
comportement le plus courant, j'ai l'impression), il va falloir aussi
définir un pointeur de « fin de fichier ».

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Tue Sep 16, 2003 9:39 am    Post subject: Re: norme : basic_stringbuf str(), et pptr() .. Reply with quote

Samuel Krempp <krempp (AT) crans (DOT) truc.en.trop.ens-cachan.fr> wrote

Quote:
le Monday 15 September 2003 13:00, [email]kanze (AT) gabi-soft (DOT) fr[/email] écrivit :

[...]
Quote:
je vois pas pquoi ils auraient fait ça plutôt que de dire que str() ne
retourne pas tout la séquence (juste [xbeg, xnext[), et comme ça
l'implémentation pouvait utiliser xend comme fin rélle de la mémoire
physiquement allouée.. à moins que ça pose problème pour spécifier le
coté get area dans le cas destringstream dans les 2 sens (mais à
priori ça devrait aussi bien se passer).

Ce qui m'inquiète là-dedans, c'est que les implémentations actuelles
semblent bien renvoyer [xbeg,xend[, et non [xbeg,xnext[. D'une part, ça
m'avait étonné, parce que ça fait une différence importante par rapport
à strstream au niveau de l'utilisation. Mais aujourd'hui, dire que
stringbuf doit renvoyer [xbeg,xnext[ risque de casser du code. Au moins
qu'on trouve une implémentation qui le fait, pour pouvoir dire que
quoiqu'on décide, on casse du code de quelqu'un:-).

Quote:
il me semble que ça corrigerait le problème du stringbuf sans toucher
au reste, en particulier à la phrase
§27.5.1.2
The array object represents, at any moment, a (sub)sequence of
characters from the sequence.

Je crois qu'il y a une correction simple ici : « The array object
*contains* a representation of a subsequence of characters from the
sequence ». C'est une différence subtile, mais ça laisse ouvert la
possibilité que la représentation n'occupe pas tout le buffer.

Mais évidemment, corriger cette phrase laisse toujours ouverte la
question de ce que stringbuf::str doit renvoyer.

Quote:
Maintenant j'imagine que c'est trop tard pour changer la spécification
de stringuf::str() de toute façon.

C'est trop tard de changer ce qui est bien spécifié. AMHA, en revanche,
la formulation actuelle ne spécifie en fait prèsque rien : elle dit que
str() renvoie la séquence. Ailleurs, la norme dit que le buffer contient
une représentation de la séquence ou d'une sousséquence de la séquence
(après la correction ci-dessus, à mon avis nécessaire). Mais il n'est
jamais dit ce que c'est réelement cette séquence -- dans le cas de
filebuf, on crois le savoir, en se rapportant au fonctionnement des
fichiers du système. Mais ça n'apporte rien ici.

Quote:
Ceci-dit, stringbuf est tout de même très singulier comme streambuf,
puisqu'il n'y a rien d'autre que le buffer.

Qu'est-ce qui te fait dire ça ? Ça vaudrait à la rigueur pour
strstreambuf, mais certainement pas pour streambuf. Il y a une
représentation « externe » qui est la chaîne. Une implémentation est
libre de n'en mettre qu'une partie dans le buffer.

Je reviens à mon image de fichier : la chaîne d'un stringbuf se comporte
exactement comme un fichier -- disque ou bande, reste à voir. Les
différences par rapport à filebuf sont d'une part, que tu peux en
obtenir une copie du « fichier » dans une std::string, et de l'autre,
c'est en fait la seule façon de voir ce qu'il y a dans le fichier (ce
qui pourrait permettre un certain nombre d'optimisations dans
l'implémentation).

Ce que je proposerais, mais ça va bien au delà de ce qu'on peut faire
dans une correction, c'est 1) conceptuellement, le std::string derrière
le stringbuf se comporte exactement comme un fichier disque en mode
binaire (sauf que la fin de fichier est garantie), et 2) on ajoute une
fonctionnalité de troncation. Conceptuellement, c'est ce qui me semble
le plus propre, le plus simple à spécifier, et le plus simple à
comprendre.

Mais vue que ça ajoute une fonction virtuelle dans l'interface de
streambuf, avec une fonctionnalité totalement absente jusqu'ici, ça ne
passe pas.

Quote:
la contorsion de faire qu'overflow arrive à chaque sputc() peut être
logique, si on voit la notion de stringbuf comme étant celle d'un
buffer où 'le buffer' _entier_ lui même _est_ la séquence (et alors
pour ça, effectivement il faut qu'overflow ne mette pas l'espace
préalloué dans le 'buffer'). Mais la moindre des choses serait que le
texte de la norme le dise un peu plus clairement.

et ça ne change pas ma critique que str() devrait plutôt renvoyer [xbeg,
xnext[

Pragmatiquement, vue les utilisations, je suis d'accord avec toi. De
toute façon, la situation actuelle a à mon avis besoin de clarification.

Quote:
Ce qu'il faut voir aussi, c'est que si le seek n'efface pas ce qui
suit, il faut bien quatre pointeurs, à la place de trois. Dans le
cas de filebuf, ça marche parce que le système d'exploitation
maintient le pointeur supplémentaire (à la fin de fichier). Dans le
cas de stringbuf, si on veut que le seek n'efface pas (ce qui est
quand même le comportement le plus courant, j'ai l'impression), il
va falloir aussi définir un pointeur de « fin de fichier ».

j'ai regardé pour g++-3.3 : le stringbuf contient un string (et
j'imagine que c'est commun à bcp d'implémentations !)

C'est une optimisation évidente d'utiliser le buffer d'un std::string
comme buffer du flux. C'est un peu délicat, mais c'est jouable, et ça
pourrait éviter des copies inutiles.

Quote:
Donc le "pointeur supplémentaire" réside dans la redondance du xend
stocké dans le streambuf général avec le string stocké dans le
stringbuf. mais effectivement c'est tt de même plus simple de
réutiliser le code de string directement, ça vaut le pointeur
supplémentaire.

Tout à fait.

Quote:
A ce propos, le fait que str() renvoit toute la séquence permet de
profiter du copy-on-write quant on a un membre string, même après
seekpos(..), vu que str() renvoit même dans ce cas une copie du string
interne.

Je ne sais pas si ça était une considération.

Quote:
C'est le seul avantage que je peux trouver à ce comportement.

L'avantage que je vois, c'est qu'un stringbuf se comporte beaucoup comme
un filebuf ouvert sur un fichier.

Quote:
Bien qu'encore, ce serait aussi possible de faire renvoyer [xbeg,
xnex[ par str(.) avec copy-on write si l'implémentation adapte sa
classe string pour permettre de partager seulement une sous-séquence
du string (c'est très simple même à mon avis)

En effet. Si j'avais à implémenter une classe string mono-thread
aujourd'hui, j'utiliserais bien copy-on-write, avec d'une part, le
compteur de références et la capacité cachés avant la texte même, et
d'autre part, une structure de données avec un pointeur vers cette
structure, un offset ou pointeur du début, et un offset ou pointeur de
fin. (Mais il faut dire qu'une des utilisations principales des chaînes
chez moi, c'est la lecture d'un fichier de configuration ou de commande,
typiquement orienté ligne, avec chaque ligne découpée en champs.)

Mais la tendance actuelle est vers du multi-thread, et l'interface de
std::string dans la norme rend une copy-on-write dans un milieu
multi-thread extrèmement chère.

Quote:
le mieux, ce serait que stringbuf fournisse 2 fonctions, str() et
partial_str() - je préfererais str() et full_str() mais évidemment ça
pose problème de legacy code.

Le mieux, ça serait d'ajouter du support pour le troncation dans tous
les streambuf:-).

Quote:
Comme ça tout le monde est content (hmmm.. sauf que partial_str() est
long à taper, moi je préfère cur_str() Smile
et l'implémentation peut faire du copy-on write pour les 2.

(alors qu'en dérivant stringbuf pour faire son partial_str() soit même
comme je l'ai fait,

schématiquement :
string_type cur_str() const { return string_type( pbase(), pptr()); }

on ne peut pas bénéficier de copy-on-write dans cet appel du
constructeur de string_type. (à moins que la classe string parvienne à
reconnaitre quels pointeurs pointent vers des chars contenus par un de
ses objets, mais ce serait très très fort, et peut être pas légal)

Je ne me casserais pas la tête en ce qui concerne le copy-on-write. Le
multi-thread reigne, et jusqu'ici, je n'ai pas vu de version de
std::string multi-thread qui utilisait copy-on-write, qui marche, et qui
n'est pas horriblement lente.

En passant, s'il s'agit de ta classe boost::format... Dans le temps où
je travaillais activement sur GB_Format, une des choses dans ma liste
TODO, c'était un streambuf optimisé pour mes utilisations. En fait, mon
idée, c'est que je crée un nouveau flux pour chaque paramètre (chose que
je crois toujours nécessaire pour des raisons de robusteté), mais que
ces flux (ou plutôt leurs streambuf) sauraient chercher les « buffers »
dans un grand buffer fixe, alloué une fois par GB_Format au début des
conversions. Et si le résultat était lu au moyen de l'opérateur <<
(comme c'est souvent le cas), je ne passais jamais par une chaîne de
caractères (std::string aujourd'hui, mais qui aurait été GB_String
alors). Je ne sais pas quelle est la situation actuelle, mais à
l'époque, c'était sûr que c'était le nombre élevé des allocations
dynamiques qui coûtait si cher. (À l'époque, j'avais fais des mésures,
et j'avais constaté que GB_Format était environ 10 fois plus lent que
sprintf. Ce n'était pas un problème dans mes applications, mais ce ne
serait sûrement pas acceptable dans une bibliothèque générale comme
Boost.)

Mais une telle solution implique pas mal de travail, et comme j'ai dit,
je n'en avais pas besoin.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ (French) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.