On 5/30/16 2:32 PM, Alex Parrill wrote:
On Monday, 30 May 2016 at 12:53:07 UTC, Steven Schveighoffer wrote:
I'm trying to figure out which cases caching makes the solution
impossible.
One case is wrapping a network stream: a TCP input range that yields
ubyte[] chunks of data as they are read from the socket, a joiner to
join the blocks together, a map that converts the bytes to characters,
and take to consume each message.
The issue is that, in a naive implementation, creating the TCP range
requires reading a chunk from the socket to populate front. Since I
usually set up my stream objects, before using them, the receiver range
will try to receive a chunk, but I haven't sent a request to the server
yet, so it would block indefinitely.
Same issue with popFront: I need to pop the bytes I've already used for
the previous request, but calling popFront would mean waiting for the
response for the next request which I haven't sent out yet.
The solution I used was to delay actually receiving the chunk until
front was called, which complicates the implementation a bit.
This is not the same issue. Note that populating on call to front
instead of on popFront is still valid within the definition of a range
(though I think the most straightforward way to implement a range is to
populate only on popFront).
What makes this awkward is that you need to check to see if front has
already been populated, which also kind of requires a separate flag
(though you may be able to do this without an extra flag). However, you
still need a place to put the data, and using a buffer for this is a
good fit.
I would suggest that custom i/o patterns like this (where calling
popFront is coupled to some other operation) do not fit ranges very
well. In the iopipe library I wrote, I have two separate operations for
"fetch more data" and "forget the oldest data", which are based on the
requirements for i/o. These can be cajoled into a range interface, of
course, but those operations suit i/o requirements much better than
front/popFront/empty.
-Steve