Adapting foreign iterators to D ranges

Salih Dincer salihdb at hotmail.com
Wed Apr 24 05:08:25 UTC 2024


On Tuesday, 23 April 2024 at 06:02:18 UTC, cc wrote:
> Just to offer an alternative solution (since it sometimes gets 
> overlooked), there is also the `opApply` approach.  You don't 
> get full forward range status, and checking whether it's empty 
> essentially requires doing something like std.algorithm 
> `walkLength`, but if all you need is basic iteration, it can be 
> a simpler solution:
>

Yes, `opApply()` works! You just need to use `do while()` instead 
of `while()` because it skips the first item.

```d
struct Node
{
   int item;
   Node* next;
}

class List
{
   Node* root, iter;

   this(int item = 0)
   {
     iter = new Node(item, null);
     root = iter;
   }

   List dup()
   {
     auto backup = new List();
     backup.root = root;
     backup.iter = iter;

     return backup;
   }

   void insertFront(T)(T item)
   {
     (*iter).next = new Node(item, null);
     this.Next;
   }

   bool empty() const => iter is null;
   auto front() inout => iter;
   auto popFront()    => iter = this.Next;
   auto getItem()     => iter.item;
   auto rewind()      => iter = root;
}

auto Next(List list) => list.iter = list.iter.next;
auto gaussian(T)(T n)=> (n * n + n) / 2;

void main()
{
   import std.stdio;
   enum LIMIT = 10;

   auto list = new List(1);
   foreach(t; 2 .. LIMIT + 1)
   {
     list.insertFront(t);
   }

   auto tmp = list.dup;
   list.rewind();

   size_t sum;
   do sum += list.getItem; while(list.Next);
   assert(gaussian(LIMIT) == sum);

   sum.writeln; // 55

   auto next = LIMIT + 1;
   tmp.insertFront(next);
   tmp.rewind();
   sum = 0;

   foreach(t; tmp) sum += t.item;
   assert(gaussian(LIMIT) + next == sum);

   sum.writeln; // 66
   tmp.rewind();

   auto range = Range(tmp);

   foreach(r; range) r.item.write(" ");
   writeln; //  2 3 4 5 6 7 8 9 10 11
   // ? (1) --^
}

struct Range
{
   private List iter;

   int opApply(scope int delegate(Node* t) dg)
   {
     while(auto current = iter.Next)
     {
       if (auto r = dg(current))
         return r;
     }
     return 0;
   }
}
```

SDB at 79




More information about the Digitalmars-d-learn mailing list