On 01/05/2012 09:27, Nick Sabalausky wrote:
A little write-up I just did on something I thought was pretty cool:

Combine Coroutines and Input Ranges for Dead-Simple D Iteration
https://www.semitwist.com/articles/article/view/combine-coroutines-and-input-ranges-for-dead-simple-d-iteration



This got me thinking, so I tried to do something a little similar myself, the result is below.

If you only have one type to iterate over, you can make the user code look even cleaner! I can't help but feel it can become even cleaner too.

(Scroll to the "User code" comment to miss out the implementation).

The code:
----
import core.thread;

class VFiber(Elem) : Fiber
{
    Elem elem;
    this(void delegate() dg)
    {
        super(dg);
    }
}

auto visitor(T, Elem = T.visitType)(T t)
{
    static struct Visitor
    {
        T t;
        VFiber!Elem f;
        @disable this();
        @disable this(this);
        this(T t)
        {
            this.t = t;
            f = new VFiber!Elem(&t.visit);
            f.call();
        }

        Elem front() @property
        {
            return f.elem;
        }

        void popFront()
        {
            f.call();
        }

        bool empty() @property
        {
            return f.state == Fiber.State.TERM;
        }
    }
    return Visitor(t);
}

void yield(Elem)(Elem el)
{
    auto f = cast(VFiber!Elem)cast(void*)Fiber.getThis();
if (f is null) throw new FiberException("Cannot yield a value from outside the visit() method");
    f.elem = el;
    Fiber.yield();
}

// User code starts here
struct Iterable
{
    string[] strs = ["hello", "world"];
    alias string visitType;

    void visit()
    {
        foreach(str; strs)
            yield(str);
    }
}

void main()
{
    import std.stdio;
    Iterable i;
    foreach(el; i.visitor)
    {
        writefln("%s", el);
    }
}
----

--
Robert
http://octarineparrot.com/

Reply via email to