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