Boost logo

Boost :

From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-03-10 16:00:00


Rob Stewart wrote:
> From: "Jonathan Turkanis" <technews_at_[hidden]>
>> Rob Stewart wrote:
>>> From: "Jonathan Turkanis" <technews_at_[hidden]>

>>> 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


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk