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.



Reply via email to