
Rob Stewart wrote:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
Rob Stewart wrote:
From: "Jonathan Turkanis" <technews@kangaroologic.com>
How about putting a state variable in filters, sources, and sinks to indicate EAGAIN, EOF, and GOOD. Then, functions that only read or write a single character can return a bool, and functions that read or write multiple characters can return a count. If the bool is false or the count is zero, the code can query the state to determine whether EAGAIN or EOF occurred. That keeps the error indication in the return value simple and even leaves room for adding additional error states should that prove necessary. Hard errors can still be signaled via exception.
This was one of the options I seriously considered. I believe the very first version of the library I posted had this feature. I tend to think it would make life harder for people writing filters and devices to force them to implement an additional function. As things stand, you can often get by with a implementing a single function, and it works pretty well. Also, it makes it harder to fit standard streams and stream bufferss into the framework: stream buffers don't have a state indicator at all; streams do, but it doesn't map well to good/eof/eagain.
Excellent points. I think your current direction is appropriate in light of these things.
Good. Thanks.
Yes, they are more readable, but if you don't document the implementation of those functions, library users will expect to use them in all situations. Thus, switching to async from sync I/O will be less of a stylistic change. (That also leaves room for you to change the implementation details if need be.)
I meant that if the library user only knows to write "eof(c)," and doesn't know that "c == EOF" is an alternative spelling because you don't document it, then the user will only ever write "eof(c)" whether they are writing a blocking or non-blocking filter.
Okay, I understand.
Whether blocking filters traffic char_traits, while non-blocking uses basic_character is a separate question, but I think the answer should be obvious: use basic_character in both places.
I agree.
Then, library users can remain oblivious to char_traits if they don't already know about it.
Or if they already know about it they can start to try to forget about it. ;-) I've started writing some non-blocking filters, and they don't look so bad, as long as they process one character at a time. So my inclination is to make all filters non-blocking except for a couple of convenience filters which process an entire document at a time. In that case, get will always return basic_character. One more possibility is this: enum eof_type { eof }; enum would_block_type { would_block }; template<typename Ch> class basic_character { basic_character(Ch = Ch()); basic_character(eof_type); basic_character(would_block_type); operator Ch () const; operator safe_bool () const; bool operator==(eof_type) const; bool operator!=(eof_type) const; bool operator==(would_block_type) const; bool operator!=(would_block_type) const; // All the other operators we discussed }; This would allow the usage: if (c == eof) { ... } if (c == would_block) { ... } How do you like this?
This is a real problem with eagain, since testing may not reveal the error unless eagain happens to occur at the right place in a character sequence.
You'll need special test sources and sinks that can be configured to produce "would_block" after N calls.
I'm think I might use file devices which process a random number of characters at a time.
You could return a special type in lieu of bool, and basic_character in lieu of char_type, which require inspecting whether they indicate an error condition. If that query is not done, the destructor can complain.
Could you elaborate? It sounds like it could lead to very poor performance.
I just mean that querying the status sets a flag in the object that the dtor checks. If the flag wasn't set, then the dtor complains. The complaint code could be an assertion or maybe a message printed on stderr. You can even conditionally compile away the checks.
That's what I though you meant. I think this might be a good idea for a debug mode. Thanks again! Jonathan