On Sunday, 7 July 2019 at 21:55:17 UTC, Jonathan M Davis wrote:
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.
Sounds like you didn't understand what I meant. So I tried to
implement what I had in mind and I have to confess, that there is
something about ranges that I do not understand yet:
import std.stdio;
import std.array;
void main()
{
auto a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
call(a,5);
}
void call(T)(ref T range, int c)
{
struct Take
{
T* take_range;
int count;
@property bool empty=false;
@property auto front() { return (*take_range).front; }
void popFront()
{
(*take_range).popFront();
if (--count<=0) empty=true;
}
T* get_range()
{
assert(count==0);
while (!empty) popFront();
return take_range;
}
}
auto take = Take(&range,c);
// writeln(take);
while (!take.empty) { write(take.front); take.popFront(); }
auto original_range = take.get_range();
writeln(*original_range);
}
Running this program leads to
12345[6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
as expected.
But when I replace that loop at the bottom by writeln(take) the
assertion in get_range fails (count==5). As all the functions are
called in the same order by both the loop and writeln, I confess,
that writeln somehow manages to use a copy of "take" although
this isn't a ForwardRange and copying should therefore not be
possible.
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,
I't not about improving or doing things different. It's just
about me understanding, what happens.