Stackless resumable functions
bitwise via Digitalmars-d
digitalmars-d at puremagic.com
Mon Feb 23 15:10:28 PST 2015
> you don't need to. if you really need to do that, you're doing
> something
This makes no sense to me. A usage example may be helpful.
> resumable functions are not iterators. it's a slightly
> perversed flow
> control method. iteration/generation is one of the use cases.
So how do you explain enumerators in C#, or generators in visual
c++?
> and, by the way, yielding is a two-way communication channel.
http://www.boost.org/doc/libs/1_57_0/libs/coroutine/doc/html/index.html
[quote]
Coroutine
Asymmetric coroutine
Symmetric coroutine
[/quote]
> you seem to stuck with iteration/generation idea, but this is
> not the way resumable functions should be seen.
Not sure what to say to this..
> mimicking delegates allows to use resumable function in any
> code that expects delegate.
If you can come up with even one example(with code) where it
would make
sense to accept both coroutines and delegates, I will be very
surprised.
In any case, I have revised my design. Generator(T) was
redundant, so I removed it. Below is something that I think is
well formed enough for me to start digging through the compiler
for specifics.
interface MethodRange(T)
{
@property T front();
void popFront();
@property bool empty();
int opApply(int delegate(T) dg);
}
class __ResumeableMethod(T, METHOD_TYPE, CONTEXT_TYPE) :
MethodRange!T
{
// method locals and passed args
CONTEXT_TYPE* context;
// -initially contains method entry point
// -once executed, contains the resume address
// -when finished, contains null
void *fptr;
// object reference for instance methods
void *obj;
T value;
this(CONTEXT_TYPE* context, void *fptr, void *obj) {
this.context = context;
this.fptr = fptr;
this.obj = obj;
invoke(context, &value);
}
private T invoke(CONTEXT_TYPE *context, T *yielded_value) {
fptr(context);
fptr = context->return_address;
if(fptr)
*yielded_value = context->yielded_value;
}
@property override T front() {
assert(!this.empty);
return value;
}
override void popFront() {
assert(!this.empty);
invoke(context, &value);
}
@property override bool empty() {
return fptr == null;
}
int opApply(int delegate(T) dg)
{
while(!this.empty)
{
if(dg(this.front))
return 1;
}
return 0;
}
}
MethodRange!int myResumableMethod()
{
for(int i = 0; i < 10; ++i)
yield i;
}
// the compiler would automatically transform the above
// method into something like the one below
MethodRange!int myResumableMethod()
{
void __method(__ContextFor__method *ctx)
{
for(ctx->i = 0; i < 10; ++i)
{
ctx->yielded_value = i;
ctx->return_address = &return_pos;
return;
return_pos:
}
ctx->return_address = null;
}
return new __ResumeableMethod!int(new __ContextFor__method,
&__method, null);
}
// usage
void main()
{
foreach(num; myResumableMethod())
writeln(num);
// or
MethodRange!int[] methods;
auto mr = myResumableMethod();
if(!mr.empty)
methods ~= mr;
for(int i = 0; i < methods.length; )
{
auto mr = methods[i];
int status = mr.front;
// handle item status..
mr.popFront();
if(mr.empty)
methods.remove(i);
else
++i;
}
}
More information about the Digitalmars-d
mailing list