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@79


Reply via email to