Is there something like a consuming take?

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sun Jul 7 21:55:17 UTC 2019


On Sunday, July 7, 2019 12:36:42 PM MDT berni via Digitalmars-d-learn wrote:
> On Sunday, 7 July 2019 at 09:01:53 UTC, Jonathan M Davis wrote:
> > Without slicing, that's impossible without iterating over the
> > elements multiple times.
>
> That's what I thought too, but meanwhile I think it is possible.
> To get it working, the second range needs to know about the first
> one and when the second one is queried the first time it has to
> notify the first one, that it has to remove all remaining items
> from the underlying range (and in case it still needs them, save
> them) and never use it again.
>
> The advantage of this setup over copying the items immediately is
> some sort of laziness. It might happen, that the second one will
> never query or it might happen, that the first one finished
> allready when the second one queries. In this cases no additional
> memory is needed.
> Even if the second one is queried before the first one finished,
> the needed buffer might be much smaller.

Having one range know about the other isn't enough. That just means that the
take range would tell the other range that it had popped an element off, and
then the other would know that it had to pop an element off. That still
involves popping the same element on different ranges twice. In order to
have popFront only called once, they have to be the same range, so when take
pops an element off, it pops an element off of the other range. If both the
take range and the drop range are wrappers, then it would be possible to do
something with pointers to the original range where the number of elements
that has been popped off is kept track of, and as long as the take range
pops them all first, the drop range can just continue iterating through the
original range, but if any elements from the drop range got iterated first,
then it would have to save the range and start popping from there not to
screw up the take range. And since pointers to the original range would have
to be used to avoid having independent copies, you run the risk of all of
this being screwed up by a piece of code popping an element from the
original range at some point. Also, all of that machinery would likely
quickly become far more expensive than simply saving the range to call take
on it and then calling drop on the original. Yes, that pops the same
elements multiple times, but wrapper ranges already end up calling chains of
popFronts, fronts, and emptys as they iterate through a range. You rarely
really get a single popFront call for a popFront unless the optimizer has
actually managed to optimize out all of the layers.

You can try mucking around with your own implemention of take if you want,
but I'd suggest that you're just better off taking the approach that it's
expected that if you use take, you're going to have to iterate through those
elements twice and that if that's not acceptable, it's better to do whatever
you need to do with the take range by manually operating on each of the
elements rather than having them be a range. Unless random-access ranges
with slicing are involved, trying to do anything that effectively slices a
range without iterating over the elements multiple times is almost certainly
going to be a mess. At some point, if you really want slicing semantics,
then you need to make sure that your range actually has slicing rather than
trying to act like it does when it doesn't.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list