| | 516 | |
|---|
| | 517 | private struct DelegateFaker(R, Args...) { |
|---|
| | 518 | R doIt(Args args) { |
|---|
| | 519 | // When this function gets called, the this pointer isn't really a |
|---|
| | 520 | // this pointer (no instance even really exists), but a function |
|---|
| | 521 | // pointer that points to the function |
|---|
| | 522 | // to be called. Cast it to the correct type and call it. |
|---|
| | 523 | |
|---|
| | 524 | auto fp = cast(R function(Args)) &this; |
|---|
| | 525 | return fp(args); |
|---|
| | 526 | } |
|---|
| | 527 | } |
|---|
| | 528 | |
|---|
| | 529 | /**Convert a function pointer to a delegate with the same parameter list and |
|---|
| | 530 | * return type, avoiding heap allocations and use of auxiliary storage. |
|---|
| | 531 | * |
|---|
| | 532 | * Examples: |
|---|
| | 533 | * --- |
|---|
| | 534 | * void doStuff() { |
|---|
| | 535 | * writeln("Hello, world."); |
|---|
| | 536 | * } |
|---|
| | 537 | * |
|---|
| | 538 | * void runDelegate(void delegate() myDelegate) { |
|---|
| | 539 | * myDelegate(); |
|---|
| | 540 | * } |
|---|
| | 541 | * |
|---|
| | 542 | * auto delegateToPass = toDelegate(&doStuff); |
|---|
| | 543 | * runDelegate(delegateToPass); // Calls doStuff, prints "Hello, world." |
|---|
| | 544 | * --- |
|---|
| | 545 | * |
|---|
| | 546 | * Bugs: Doesn't work properly with ref return. (See DMD bug 3756.) |
|---|
| | 547 | */ |
|---|
| | 548 | auto toDelegate(F)(F fp) { |
|---|
| | 549 | |
|---|
| | 550 | // Workaround for DMD Bug 1818. |
|---|
| | 551 | mixin("alias " ~ ReturnType!(F).stringof ~ |
|---|
| | 552 | " delegate" ~ ParameterTypeTuple!(F).stringof ~ " DelType;"); |
|---|
| | 553 | |
|---|
| | 554 | version(none) { |
|---|
| | 555 | // What the code would be if it weren't for bug 1818: |
|---|
| | 556 | alias ReturnType!(F) delegate(ParameterTypeTuple!(F)) DelType; |
|---|
| | 557 | } |
|---|
| | 558 | |
|---|
| | 559 | static struct DelegateFields { |
|---|
| | 560 | union { |
|---|
| | 561 | DelType del; |
|---|
| | 562 | pragma(msg, typeof(del)); |
|---|
| | 563 | |
|---|
| | 564 | struct { |
|---|
| | 565 | void* contextPtr; |
|---|
| | 566 | void* funcPtr; |
|---|
| | 567 | } |
|---|
| | 568 | } |
|---|
| | 569 | } |
|---|
| | 570 | |
|---|
| | 571 | // fp is stored in the returned delegate's context pointer. The returned |
|---|
| | 572 | // delegate's function pointer points to DelegateFaker.doIt. |
|---|
| | 573 | DelegateFields df; |
|---|
| | 574 | df.contextPtr = cast(void*) fp; |
|---|
| | 575 | |
|---|
| | 576 | DelegateFaker!(ReturnType!(F), ParameterTypeTuple!(F)) dummy; |
|---|
| | 577 | auto dummyDel = &(dummy.doIt); |
|---|
| | 578 | df.funcPtr = dummyDel.funcptr; |
|---|
| | 579 | |
|---|
| | 580 | return df.del; |
|---|
| | 581 | } |
|---|
| | 582 | |
|---|
| | 583 | unittest { |
|---|
| | 584 | static int inc(ref uint num) { |
|---|
| | 585 | num++; |
|---|
| | 586 | return 8675309; |
|---|
| | 587 | } |
|---|
| | 588 | |
|---|
| | 589 | uint myNum = 0; |
|---|
| | 590 | auto incMyNumDel = toDelegate(&inc); |
|---|
| | 591 | static assert(is(typeof(incMyNumDel) == int delegate(ref uint))); |
|---|
| | 592 | auto returnVal = incMyNumDel(myNum); |
|---|
| | 593 | assert(myNum == 1); |
|---|
| | 594 | } |
|---|