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 

putback breaks the stream state?

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Alexander Kamotsky
Guest





PostPosted: Mon Nov 15, 2004 11:42 am    Post subject: putback breaks the stream state? Reply with quote



Hi, all!

I'm getting the ifstream state setting to bad and fail in the
following program (see below). I suspect there's some "feature" in
putback I don't know about or missed. May be putback isn't always
available?

The demo below stops and prints "### bad fail", where ### is some line
number, different for every text file. Text files I give it on input
are usually without empty lines and contain more than 1000 lines.

Five chars I putback are just a "magic number" to make program stop
sooner (for example, at line 25, 140 or 245).


std::ifstream s ("a.txt");

for (int line = 0; line < 1000; ++line)
{
ios_base::iostate st = s.rdstate();
if (st != ios_base::goodbit)
{
cout << line << " ";
if (st & ios_base::goodbit) cout << "good ";
if (st & ios_base::badbit) cout << "bad ";
if (st & ios_base::eofbit) cout << "eof ";
if (st & ios_base::failbit) cout << "fail ";
return 0;
}

char c[5];
s.get(c[0]);
s.get(c[1]);
s.get(c[2]);
s.get(c[3]);
s.get(c[4]);
s.putback(c[4]);
s.putback(c[3]);
s.putback(c[2]);
s.putback(c[1]);
s.putback(c[0]);

// skip the line
std::string ss; getline(s, ss);

} // for line...

So, what's happening and how should I control it?

Actually, my real program looks a bit different and maybe you can
advice another approach at all? =)

I'm trying to read some named variables from a text file in the
following way:

s >> Pattern(" rl=") >> rect.left;
s >> Pattern(" rt=") >> rect.top;
s >> Pattern(" rw=") >> rect.width;
s >> Pattern(" rh=") >> rect.height;

try {
s >> Pattern(" orl=") >> orect.left;
s >> Pattern(" ort=") >> orect.top;
s >> Pattern(" orw=") >> orect.width;
s >> Pattern(" orh=") >> orect.height;
}
catch (Pattern::Exception::CantReadPattern&)
{
// Usually thrown by first " orl="-mask reader.
// Obsolete file format - no orect field.
// Just ignoring the exception.
}

Each Pattern object tries to read a mask (using strange-looking
operator >> (istream& s, _const_ Pattern& p)), or to put the chars
it read back into the stream, if they are not match a mask.

--
Best regards,
Alexander mailto:alexandroid (AT) p5com (DOT) com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Wed Nov 17, 2004 2:06 am    Post subject: Re: putback breaks the stream state? Reply with quote



Alexander Kamotsky <alexandroid (AT) p5com (DOT) com> wrote


Quote:
I'm getting the ifstream state setting to bad and fail in the
following program (see below). I suspect there's some "feature" in
putback I don't know about or missed. May be putback isn't always
available?

At least one character putback is always available. Any more depends on
the implementation, and may or may not be available.

Quote:
The demo below stops and prints "### bad fail", where ### is some line
number, different for every text file. Text files I give it on input
are usually without empty lines and contain more than 1000 lines.

Five chars I putback are just a "magic number" to make program stop
sooner (for example, at line 25, 140 or 245).

Five character putback may fail. A stream is only required to support
one character look-ahead. The "default" implementation of pushback (in
streambuf) is to try to do it by adjusting pointers into the buffer, and
fail if this doesn't succeed. This means that pushing back five
characters will succeed unless your starting position happens to be
within the first five characters of the buffer.

If you need more pushback, the easiest solution is probably just to
write a filtering streambuf which supports unlimited pushback, using a
separate look-aside buffer (probably an std::stack) for the pushback.

Depending on the application, it might also be appropriate to wrap the
istream is a higher level class, which could also handle the putback.

--
James Kanze GABI Software http://www.gabi-soft.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Thu Nov 18, 2004 12:00 am    Post subject: Re: putback breaks the stream state? Reply with quote



Alexander Kamotsky wrote:
Quote:
s >> Pattern(" rl=") >> rect.left;
s >> Pattern(" rt=") >> rect.top;
s >> Pattern(" rw=") >> rect.width;
s >> Pattern(" rh=") >> rect.height;

try {
s >> Pattern(" orl=") >> orect.left;
s >> Pattern(" ort=") >> orect.top;
s >> Pattern(" orw=") >> orect.width;
s >> Pattern(" orh=") >> orect.height;
}
catch (Pattern::Exception::CantReadPattern&)
{
// Usually thrown by first " orl="-mask reader.
// Obsolete file format - no orect field.
// Just ignoring the exception.
}

Each Pattern object tries to read a mask (using strange-looking
operator >> (istream& s, _const_ Pattern& p)), or to put the chars
it read back into the stream, if they are not match a mask.


Other that James Kanze's suggestions, I'd like to suggest another one: you
can attach arbitrary data via the iword/pword/xalloc functions of
iostreams.

int get_index()
{
// reserve an index(globally!)
static const int index = std::ios_base::xalloc();
return index;
}

std::string peek_tag( std::istream& in)
{
// note the reference here!
void*& p = in.pword( get_index());
if(!p)
{
// allocate and read a tag and attach it to the stream
std::string tag;
std::getline( in, '=');
p = new std::string(tag);
}
return static_cast<std::string*>(p);
}

std::string get_tag( std::istream& in)
{
// note the reference here!
void*& p = in.pword( get_index());
if(!p)
{
// read and return a new tag
std::string tag;
std::getline( in, '=');
return tag;
}
// detach and return an previously read tag
std::string* tag = static_cast<std::string*>(p);
p = 0;
std::string res(*tag);
delete tag;
return res;
}

Disclaimer: This small example here lacks a bit of error-handling, some
callbacks that will release the memory for the tag when the stream is
destroyed and is untested and uncompiled.

I have successfully used this technique in a case where I needed a larger
lookahead than is guaranteed by std::streams, just like the OP. I believe
the biggest drawback is that after prefetching a tag, you could read things
from a stream and, later, have the tag appear in a different place than
where it was. I'm interested in your opinions on this matter, and whether I
should have done something different.

thanks

Uli

--
FAQ: http://parashift.com/c++-faq-lite/
/* bittersweet C++ */
default: break;


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Alexander Kamotsky
Guest





PostPosted: Fri Nov 19, 2004 4:56 pm    Post subject: Re[2]: putback breaks the stream state? Reply with quote

Thursday, November 18, 2004, 2:00:41 AM, Ulrich Eckhardt wrote:

Quote:
s >> Pattern(" orl=") >> orect.left;

Each Pattern object tries to read a mask (using strange-looking
operator >> (istream& s, _const_ Pattern& p)), or to put the chars
it read back into the stream, if they are not match a mask.

UE> Other that James Kanze's suggestions, I'd like to suggest another
UE> one: you can attach arbitrary data via the iword/pword/xalloc
UE> functions of iostreams.

UE> int get_index()
UE> std::string peek_tag( std::istream& in)
UE> std::string get_tag( std::istream& in)

UE> Disclaimer: This small example here lacks a bit of error-handling,
UE> some callbacks that will release the memory for the tag when the
UE> stream is destroyed and is untested and uncompiled.

UE> I have successfully used this technique in a case where I needed a
UE> larger lookahead than is guaranteed by std::streams, just like the
UE> OP. I believe the biggest drawback is that after prefetching a
UE> tag, you could read things from a stream and, later, have the tag
UE> appear in a different place than where it was. I'm interested in
UE> your opinions on this matter, and whether I should have done
UE> something different.

I can't see any "lookahead features" in these functions. =
As I understand, they let you to read some tag in one moment, and to
check out it's name later. But what the purpose of this? To read some
named fields and return as a map or something? But why to store this
data inside of the stream?

I thought xalloc/iword/pword are indended to store some state
information used by some custom manipulators. Your idea seems to offer
something different. Can you show an example of use of the get_index,
peek_tag and get_tag (the techinque itself =))? And what is OP? =)

--
Best regards,
Alexander mailto:alexandroid (AT) p5com (DOT) com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Alexander Kamotsky
Guest





PostPosted: Fri Nov 19, 2004 4:56 pm    Post subject: Re[2]: putback breaks the stream state? Reply with quote

Wednesday, November 17, 2004, 4:06:21 AM, James Kanze wrote:

Quote:
Five chars I putback are just a "magic number" to make program stop
sooner (for example, at line 25, 140 or 245).

JK> Five character putback may fail. A stream is only required to
JK> support one character look-ahead. The "default" implementation of
JK> pushback (in streambuf) is to try to do it by adjusting pointers
JK> into the buffer, and fail if this doesn't succeed. This means that
JK> pushing back five characters will succeed unless your starting
JK> position happens to be within the first five characters of the
JK> buffer.

I've suspected something like this. Thanks! =)

JK> If you need more pushback, the easiest solution is probably just
JK> to write a filtering streambuf which supports unlimited pushback,
JK> using a separate look-aside buffer (probably an std::stack) for
JK> the pushback.

JK> Depending on the application, it might also be appropriate to wrap
JK> the istream is a higher level class, which could also handle the
JK> putback.

Well, after some dancing with a tambourine I've got rid of some
non-predictible test failures caused by this problem. But then I
realized that I can simply seek (seekg) the stream back instead of
putback-ing.

s >> Pattern(" x coord=") >> x;

The whole thing about this -- rewriting some formatted file reading
without fscanf-s, but using streams. So, fortunately, putbacks are not
necessary in this case.

Whatever, thank you for the suggestions! Next time I'll be armed and
guided. =)

--
Best regards,
Alexander Kamotsky mailto:alexandroid (AT) p5com (DOT) com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Mon Nov 22, 2004 9:36 pm    Post subject: Re: Re[2]: putback breaks the stream state? Reply with quote

Alexander Kamotsky wrote:
Quote:
As I understand, they let you to read some tag in one moment, and to
check out it's name later. But what the purpose of this? To read some
named fields and return as a map or something? But why to store this
data inside of the stream?

I thought xalloc/iword/pword are indended to store some state
information used by some custom manipulators. Your idea seems to offer
something different. Can you show an example of use of the get_index,
peek_tag and get_tag (the techinque itself =))?

Right, I assume you read a series of 'key=value', and sometimes while
reading the key part of it decide you should not have read it after all,
because you expected a different one. Since you can't put the chars back
into the stream with the normal putback(), the idea is to attach them to
the stream via xalloc/pword. The next time you read a tag, you can then
check if there is already a tag attached to the stream and then continue
with that.
It is basically an external putback-buffer.

Quote:
And what is OP? =)

You, meaning O_riginal P_oster(the one that started a thread) in usenetian.
(=

Uli

--
FAQ: http://parashift.com/c++-faq-lite/

/* bittersweet C++ */
default: break;

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) 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.