On Tuesday, 24 October 2017 at 19:05:02 UTC, Martin Nowak wrote:
On Tuesday, 24 October 2017 at 14:47:02 UTC, Steven
Schveighoffer wrote:
iopipe provides "infinite" lookahead, which is central to its
purpose. The trouble with bolting that on top of ranges, as
you said, is that we have to copy everything out of the range,
which necessarily buffers somehow (if it's efficient i/o), so
you are double buffering. iopipe's purpose is to get rid of
this unnecessary buffering. This is why it's a great fit for
being the *base* of a range.
In other words, if you want something to have optional
lookahead and range support, it's better to start out with an
extendable buffering type like an iopipe, and bolt ranges on
top, vs. the other way around.
Arguably this it is somewhat hacky to use a range as end marker
for slicing sth., but you'd get the same benefit, access to the
random buffer with zero-copying.
auto beg = rng.save; // save current position
auto end = rng.find("bla"); // lookahead using popFront
auto window = beg[0 .. end]; // get a random access window to
underlying buffer
I had a design like that except save returned a “mark” (not full
range) and there was a slice primitive. It even worked with
patched std.regex, but at a non-zero performance penalty.
I think that maintaining the illusion of a full copy of range
when you do “save” for buffered I/O stream is too costly. Because
a user can now legally advance both - you need to RC buffers
behind the scenes with separate “pointers” for each range that
effectively pin them.
So basically forward ranges with slicing.
At least that would require to extend all algorithms with
`extend` support, though likely you could have a small extender
proxy range for IOPipes.
Note that rng could be a wrapper around unbuffered IO reads.