| |
| Posted by Petar Kirov [ZombineDev] in reply to Timon Gehr | PermalinkReply |
|
Petar Kirov [ZombineDev]
Posted in reply to Timon Gehr
| On Wednesday, 8 December 2021 at 07:55:55 UTC, Timon Gehr wrote:
> On 08.12.21 03:05, Andrey Zherikov wrote:
> On Tuesday, 7 December 2021 at 18:50:04 UTC, Ali Çehreli wrote:
> I don't know whether the workaround works with your program but that delegate is the equivalent of the following struct (the struct should be faster because there is no dynamic context allocation). Note the type of 'dg' is changed accordingly:
The problem with struct-based solution is that I will likely be stuck with only one implementation of delegate (i.e. opCall implementation). Or I'll have to implement dispatching inside opCall based on some "enum" by myself which seems weird to me. Do I miss anything?
This seems to work, maybe it is closer to what you are looking for.
import std.stdio, std.traits, core.lifetime;
struct CtDelegate(R,T...){
void* ctx;
R function(T,void*) fp;
R delegate(T) get(){
R delegate(T) dg;
dg.ptr=ctx;
dg.funcptr=cast(typeof(dg.funcptr))fp;
return dg;
}
alias get this;
this(void* ctx,R function(T,void*) fp){ this.ctx=ctx; this.fp=fp; }
R opCall(T args){ return fp(args,ctx); }
}
auto makeCtDelegate(alias f,C)(C ctx){
static struct Ctx{ C ctx; }
return CtDelegate!(ReturnType!(typeof(f)),ParameterTypeTuple!f[0..$-1])(new Ctx(forward!ctx),
(ParameterTypeTuple!f[0..$-1] args,void* ctx){ auto r=cast(Ctx*)ctx; return f(r.ctx,forward!args); });
}
struct A{
CtDelegate!void[] dg;
}
auto createDelegate(string s){
return makeCtDelegate!((string s){ s.writeln; })(s);
}
A create(){
A a;
a.dg ~= createDelegate("hello");
a.dg ~= createDelegate("buy");
return a;
}
void main(){
static a = create();
foreach(dg; a.dg)
dg();
}
Incidentally, yesterday I played with a very similar solution. Here's my version:
https://run.dlang.io/gist/PetarKirov/f347e59552dd87c4c02d0ce87d0e9cdc?compiler=dmd
interface ICallable
{
void opCall() const;
}
auto makeDelegate(alias fun, Args...)(auto ref Args args)
{
return new class(args) ICallable
{
Args m_args;
this(Args p_args) { m_args = p_args; }
void opCall() const { fun(m_args); }
};
}
alias Action = void delegate();
Action createDelegate(string s)
{
import std.stdio;
return &makeDelegate!((string str) => writeln(str))(s).opCall;
}
struct A
{
Action[] dg;
}
A create()
{
A a;
a.dg ~= createDelegate("hello");
a.dg ~= createDelegate("buy");
return a;
}
void main()
{
enum a = create();
foreach(dg; a.dg)
dg();
}
|