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