diff --git a/std/concurrency.d b/std/concurrency.d index 44b5918be3f..4bff9020c1c 100644 --- a/std/concurrency.d +++ b/std/concurrency.d @@ -70,6 +70,7 @@ import core.sync.condition; import core.sync.mutex; import core.thread; import std.range.primitives; +import std.range.interfaces : InputRange; import std.traits; private @@ -1496,7 +1497,8 @@ private interface IsGenerator {} * } * --- */ -class Generator(T) : Fiber, IsGenerator +class Generator(T) : + Fiber, IsGenerator, InputRange!T { /** * Initializes a generator object which is associated with a static @@ -1585,13 +1587,52 @@ class Generator(T) : Fiber, IsGenerator } /** - * Returns the most recently generated value. + * Returns the most recently generated value by shallow copy. */ final T front() @property { return *m_value; } + /** + * Returns the most recently generated value without executing a + * copy contructor. Will not compile for element types defining a + * postblit, because Generator does not return by reference. + */ + final T moveFront() + { + static if (!hasElaborateCopyConstructor!T) + { + return front; + } + else + { + static assert(0, + "Fiber front is always rvalue and thus cannot be moved since it defines a postblit."); + } + } + + final int opApply(scope int delegate(T) loopBody) + { + int broken; + for (; !empty; popFront()) + { + broken = loopBody(front); + if (broken) break; + } + return broken; + } + + final int opApply(scope int delegate(size_t, T) loopBody) + { + int broken; + for (size_t i; !empty; ++i, popFront()) + { + broken = loopBody(i, front); + if (broken) break; + } + return broken; + } private: T* m_value; } @@ -1668,6 +1709,39 @@ void yield(T)(T value) testScheduler(new ThreadScheduler); testScheduler(new FiberScheduler); } +/// +@system unittest +{ + import std.range; + + InputRange!int myIota = iota(10).inputRangeObject; + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + //can be assigned to std.range.interfaces.InputRange directly + myIota = new Generator!int( + { + foreach (i; 0 .. 10) yield(i); + }); + + myIota.popFront(); + myIota.popFront(); + assert(myIota.moveFront == 2); + assert(myIota.front == 2); + myIota.popFront(); + assert(myIota.front == 3); + + size_t[2] counter = [0, 0]; + foreach (i, unused; myIota) counter[] += [1, i]; + + assert(myIota.empty); + assert(counter == [7, 21]); +} private {