
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