Boost logo

Boost :

From: Jonathan Turkanis (technews_at_[hidden])
Date: 2005-03-03 14:32:55


Peter Dimov wrote:

> I haven't looked at the library in detail (but I have developed
> something similar).
>
> In my opinion, get and put are non-essential functions, syntactic
> sugar for read and write. put(c) is just write(&c, 1); get() is
> read(&tmp, 1); return tmp. I wouldn't worry much about the "proper"
> interface of put and get, and
> I wouldn't require filters to implement them. A get() returning -1
> for EOF and -2 for "no input available" should be good enough for
> character-at-a-time filters, which are mostly of the form "return
> xform( get() );".
>
> In fact, a character-by-character filter is never the proper way to do
> things; the canonical form of the above should be
>
> int r = read(buffer, size);
>
> if( r > 0 )
> std::transform(buffer, buffer+r, buffer, xform);
>
> return r;
>
> so I'm not sure whether get/put should ever be used at all.

Filters with member functions get() and put() are allowed for convenience; users
are incouraged to write multi-character filters which implement read() and/or
write(). You might think it's completely trivial to tranform a filter which
implements get() or put() into a filter which implements read() or write();
however, if get() or put() has multiple return statements or calls itself
recursively, sometimes it's a bit tricky.

The real need for get/put is as non-member functions used to implement filters.
Even if a filter is given a mutli-character request to process, often it must
still handle characters one at a time, using get/put applied to the next
downstream device.
As you say, read or write with single character buffers can be used instead, but
it's often easier to use get or put.

For example, if I rewrite the following to use read instead of get

    template<typename Source>
    character get(Source& src)
    {
        character c = io::get(src);
        if (c.good() && c == comment_char_)
            while (c.good() && c != '\n')
                c = io::get(src);
        return c;
    }

I end up with something like this (untested):

    template<typename Source>
    character get(Source& src)
    {
        char c;
        streamsize amt;
        if ((amt = io::read(src, &c, 1)) != 1)
            return amt == -1 ? eof() : fail();
        if (c == comment_char_) {
            while (amt == 1 && c != '\n')
                amt = io::read(src, &c, 1);
            if (amt != 1)
                return amt == -1 ? eof() : fail();
        }
        return c;
    }

If I rework it to implement read() instead of get(), I end up with this
(untested):

    template<typename Source>
    streamsize read(Source& src, char* s, streamsize n)
    {
        streamsize m = 0;
        while (m < n) {
            char c;
            streamsize amt = io::read(src, &c, 1);
            if (amt != 1)
                return m == 0 && amt == -1 ? -1 : m;
            if (c == comment_char_) {
                while (amt == 1 && c != '\n')
                    amt = io::read(src, &c, 1);
                if (amt != 1)
                    return m == 0 && amt == -1 ? -1 : m;
            }
            s[m++] = c;
        }
        return m;
    }

Perhaps the above can be simplified. The fact that it's not completely trivial
makes me relcutant to abolish get() and put().

Jonathan


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