Adapting foreign iterators to D ranges
Chloé
chloekek at use.startmail.com
Mon Apr 22 11:36:43 UTC 2024
Assume a third-party API of the following signature:
T* next(I iter);
which advances an iterator of sorts and returns the next element, or
null when iteration is done. No other information about the state of the
iterator is available.
I wish to adapt this interface to a forward range for use with foreach
and Phobos' range utilities. This amounts to implementing empty, front,
and popFront, in terms of next and some state. But there is a choice to
be made regarding the first call to next.
One could call next during range construction:
struct Range
{
private I iter;
private T* current;
this(I iter) { this.iter = iter; current = next(iter); }
bool empty() const => current is null;
inout(T)* front() inout => current;
void popFront() { current = next(iter); }
}
Or do not call it until the first call to empty:
struct Range
{
private bool initialized;
private I iter;
private T* current;
this(I iter) { this.iter = iter; }
bool empty()
{
if (!initialized) {
current = next(iter);
initialized = true;
}
return current is null;
}
inout(T)* front() inout => current;
void popFront() { current = next(iter); }
}
The first implementation has the advantage is being simpler and empty
being const, but has the downside that next is called even if the range
ends up not being used. Is either approach used consistently across the
D ecosystem?
More information about the Digitalmars-d-learn
mailing list