Skip to content

Commit 2402e9d

Browse files
committed
support ref attribute
1 parent 810dc95 commit 2402e9d

2 files changed

Lines changed: 153 additions & 59 deletions

File tree

source/openmethods.d

Lines changed: 151 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -301,21 +301,25 @@ mixin(registerMethods);
301301

302302
auto registerMethods(string moduleName = __MODULE__)
303303
{
304-
return format("static import openmethods;"
305-
~ "mixin(openmethods._registerMethods!(%s));"
306-
~ "mixin openmethods._registerSpecs!(%s);\n",
307-
moduleName, moduleName);
304+
return `static import openmethods;
305+
import std.traits : FunctionAttribute;
306+
mixin(openmethods._registerMethods!(%s));
307+
mixin openmethods._registerSpecs!(%s);`.format(moduleName, moduleName);
308308
}
309309

310310
mixin template declareMethod(string index, ReturnType, string name, ParameterType...)
311311
{
312-
mixin(openmethods._declareMethod!(index, ReturnType, name, ParameterType));
312+
mixin(openmethods.Method!(index, ReturnType, name,
313+
FunctionAttribute.none, ParameterType)
314+
.code);
313315
}
314316

315317
mixin template declareMethod(ReturnType, string name, ParameterType...)
316318
{
317-
mixin openmethods.declareMethod!(openmethods.MptrInDeallocator, ReturnType, name,
318-
ParameterType);
319+
import std.traits;
320+
mixin(openmethods.Method!(openmethods.MptrInDeallocator, ReturnType, name,
321+
FunctionAttribute.none, ParameterType)
322+
.code);
319323
}
320324

321325
mixin template defineMethod(alias Dispatcher, alias Fun)
@@ -468,9 +472,9 @@ setMethodErrorHandler(void function(MethodError error) handler)
468472
enum IsVirtual(T) = false;
469473
enum IsVirtual(T : virtual!U, U) = true;
470474

471-
private alias VirtualType(T : virtual!U, U) = U;
475+
alias VirtualType(T : virtual!U, U) = U;
472476

473-
private template VirtualArity(QP...)
477+
template VirtualArity(QP...)
474478
{
475479
static if (QP.length == 0) {
476480
enum VirtualArity = 0;
@@ -550,14 +554,22 @@ template castArgs(T...)
550554
immutable MptrInDeallocator = "deallocator";
551555
immutable MptrViaHash = "hash";
552556

553-
struct Method(string Mptr, R, string id, T...)
557+
struct Method(string Mptr, R, string id, FunctionAttribute functionAttributes_, T...)
554558
{
555559
alias QualParams = T;
556560
alias Params = CallParams!T;
557-
alias R function(Params) Spec;
558561
alias ReturnType = R;
559562
alias Word = Runtime.Word;
560563
enum name = id;
564+
alias functionAttributes = functionAttributes_;
565+
alias This = Method!(Mptr, R, id, functionAttributes, T);
566+
567+
568+
static if (functionAttributes & FunctionAttribute.ref_) {
569+
alias ref R function(Params) Spec;
570+
} else {
571+
alias R function(Params) Spec;
572+
}
561573

562574
static __gshared Runtime.MethodInfo info;
563575

@@ -679,32 +691,81 @@ struct Method(string Mptr, R, string id, T...)
679691
}
680692
}
681693

682-
static auto dispatcher(CallParams!T args)
683-
{
684-
debug(traceCalls) {
685-
stderr.write(info.name);
686-
}
694+
enum code = discriminatorCode ~ dispatcherCode;
687695

688-
alias Word = Runtime.Word;
689-
assert(info.slotStride);
696+
enum discriminatorCode = `openmethods.%s %s(openmethods.MethodTag, %s);
697+
`.format(This.stringof,
698+
name,
699+
Params.stringof[1..$-1]
700+
);
690701

691-
static if (VirtualArity!QualParams == 1) {
692-
auto mptr = Indexer!(QualParams).unary(args);
693-
debug(traceCalls) {
694-
stderr.writef("%s %s", mptr, info.slotStride[0].i);
695-
}
696-
auto pf = cast(Spec) mptr[info.slotStride[0].i].p;
697-
} else {
698-
auto pf =
699-
cast(Spec) Indexer!(QualParams).move(info.slotStride, args).p;
702+
enum refAttribute = functionAttributes & FunctionAttribute.ref_ ? "ref " : "";
703+
704+
enum string nonRefAttributes= `%s%s%s%s%s%s`
705+
.format(
706+
functionAttributes & FunctionAttribute.pure_ ? " pure" : "",
707+
functionAttributes & FunctionAttribute.nothrow_ ? " nothrow" : "",
708+
functionAttributes & FunctionAttribute.trusted ? " @trusted" : "",
709+
functionAttributes & FunctionAttribute.safe ? " @safe" : "",
710+
functionAttributes & FunctionAttribute.nogc ? " @nogc" : "",
711+
functionAttributes & FunctionAttribute.system ? " @system" : "");
712+
713+
static string dispatcherCode() {
714+
string params;
715+
string args;
716+
string sep = "";
717+
718+
foreach (i, p; Params) {
719+
args ~= `%sarg%d`.format(sep, i);
720+
params ~= `%s%s arg%d`.format(sep, p.stringof, i);
721+
sep = ", ";
700722
}
701723

724+
return `
725+
%s%s %s(%s)%s%s%s%s%s%s
726+
{
727+
import std.traits, openmethods;
728+
729+
debug(traceCalls) {
730+
import std.stdio;
731+
stderr.write(info.name);
732+
}
733+
734+
alias Word = Runtime.Word;
735+
alias Method = openmethods.%s;
736+
assert(Method.info.slotStride);
737+
738+
static if (openmethods.VirtualArity!(Method.QualParams) == 1) {
739+
auto mptr = Method.Indexer!(Method.QualParams).unary(%s);
702740
debug(traceCalls) {
703-
writefln(" pf = %s", pf);
741+
stderr.writef("%%s %%s", mptr, Method.info.slotStride[0].i);
704742
}
743+
auto pf = cast(Method.Spec) mptr[Method.info.slotStride[0].i].p;
744+
} else {
745+
auto pf =
746+
cast(Method.Spec) Method.Indexer!(Method.QualParams).move(Method.info.slotStride, %s).p;
747+
}
748+
749+
debug(traceCalls) {
750+
import std.stdio;
751+
writefln(" pf = %%s", pf);
752+
}
705753
706-
assert(pf);
707-
return pf(args);
754+
assert(pf);
755+
return pf(%s);
756+
}
757+
`.format(functionAttributes & FunctionAttribute.ref_ ? "ref " : "",
758+
ReturnType.stringof,
759+
name,
760+
params,
761+
functionAttributes & FunctionAttribute.pure_ ? " pure" : "",
762+
functionAttributes & FunctionAttribute.nothrow_ ? " nothrow" : "",
763+
functionAttributes & FunctionAttribute.trusted ? " @trusted" : "",
764+
functionAttributes & FunctionAttribute.safe ? " @safe" : "",
765+
functionAttributes & FunctionAttribute.nogc ? " @nogc" : "",
766+
functionAttributes & FunctionAttribute.system ? " @system" : "",
767+
This.stringof,
768+
args, args, args);
708769
}
709770

710771
shared static this() {
@@ -879,16 +940,16 @@ struct Runtime
879940

880941
Metrics update()
881942
{
943+
// Create a Method object for each method. Create a Class object for all
944+
// the classes or interfaces that occur as virtual parameters in a method,
945+
// or were registered explicitly with 'registerClasses'.
946+
882947
seed();
883948

884-
foreach (ci; additionalClasses) {
885-
if (ci !in classMap) {
886-
auto c = classMap[ci] = new Class(ci);
887-
debug(explain) {
888-
writefln(" %s", c.name);
889-
}
890-
}
891-
}
949+
// Create a Class object for all the classes or interfaces that derive from
950+
// a class or interface that occur as virtual parameters in a method,
951+
// or were registered explicitly with 'registerClasses'. Also record in
952+
// each Class object all the method parameters that target it.
892953

893954
debug(explain) {
894955
writefln("Scooping...");
@@ -900,11 +961,32 @@ struct Runtime
900961
}
901962
}
902963

964+
// Fill the 'directBases' and 'directDerived' arrays in the Class objects.
965+
903966
initClasses();
967+
968+
// Copy the Class objects to the 'classes' array, ensuring that derived
969+
// classes and interface come after their base class and interfaces, but as
970+
// close to them as possible.
904971
layer();
972+
973+
// Fill the 'conforming' arrays, i.e. for each class record all the classes
974+
// and interfaces that are type compatible with it. Note that every class
975+
// is in its own 'conforming' array.
976+
905977
calculateInheritanceRelationships();
978+
979+
// Check if there are classes that define the 'delete' operator.
980+
906981
checkDeallocatorConflicts();
982+
983+
// For each method, reserve one slot per virtual parameter in the target
984+
// Class.
985+
907986
allocateSlots();
987+
988+
// Build dispatch tables and install the global vectors.
989+
908990
buildTables();
909991

910992
if (methodsUsingHash) {
@@ -958,6 +1040,15 @@ struct Runtime
9581040
debug(explain) {
9591041
writeln();
9601042
}
1043+
1044+
foreach (ci; additionalClasses) {
1045+
if (ci !in classMap) {
1046+
auto c = classMap[ci] = new Class(ci);
1047+
debug(explain) {
1048+
writefln(" %s", c.name);
1049+
}
1050+
}
1051+
}
9611052
}
9621053

9631054
bool scoop(ClassInfo ci)
@@ -1607,6 +1698,7 @@ struct Runtime
16071698
}
16081699
}
16091700
}
1701+
16101702
foreach (spec; m.specs) {
16111703
auto nextSpec = findNext(spec, m.specs);
16121704
*spec.info.nextPtr = nextSpec ? nextSpec.info.pf : null;
@@ -1680,7 +1772,9 @@ version (GNU) {
16801772
string _registerMethods(alias MODULE)()
16811773
{
16821774
import std.array;
1775+
16831776
string[] code;
1777+
16841778
foreach (m; __traits(allMembers, MODULE)) {
16851779
static if (is(typeof(__traits(getOverloads, MODULE, m)))) {
16861780
foreach (o; __traits(getOverloads, MODULE, m)) {
@@ -1694,13 +1788,19 @@ string _registerMethods(alias MODULE)()
16941788
}
16951789

16961790
auto meth =
1697-
format(`openmethods.Method!("%s", %s, "%s", %s)`,
1791+
format(`openmethods.Method!("%s", %s, "%s", %s, %s)`,
16981792
index,
16991793
ReturnType!o.stringof,
17001794
m,
1795+
functionAttributes!o,
17011796
Parameters!o.stringof[1..$-1]);
1702-
code ~= format(`alias %s = %s.dispatcher;`, m, meth);
1703-
code ~= format(`alias %s = %s.discriminator;`, m, meth);
1797+
//code ~= format(`alias %s = %s.dispatcher;`, m, meth);
1798+
// alias Method = openmethods.Method!(index, ReturnType, m, functionAttributes!o, Parameters!o);
1799+
alias Method = openmethods.Method!(index, ReturnType!o, m, functionAttributes!o, Parameters!o);
1800+
//code ~= `mixin(%s.code);`.format(meth);
1801+
code ~= Method.dispatcherCode;
1802+
code ~= Method.discriminatorCode;
1803+
//code ~= format(`alias %s = %s.discriminator;`, m, meth);
17041804
}
17051805
}
17061806
}
@@ -1716,14 +1816,20 @@ mixin template _registerSpecs(alias MODULE)
17161816
{
17171817
static struct Register {
17181818

1719-
static wrapper = function Meth.ReturnType(Meth.Params args) {
1720-
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
1721-
};
1819+
static if (Meth.functionAttributes & FunctionAttribute.ref_) {
1820+
static ref Meth.ReturnType wrapper(Meth.Params args) {
1821+
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
1822+
}
1823+
} else {
1824+
static Meth.ReturnType wrapper(Meth.Params args) {
1825+
return Fun(openmethods.castArgs!(Meth.QualParams).To!(Parameters!Fun).arglist(args).expand);
1826+
}
1827+
}
17221828

17231829
static __gshared Runtime.SpecInfo si;
17241830

17251831
shared static this() {
1726-
si.pf = cast(void*) wrapper;
1832+
si.pf = cast(void*) &wrapper;
17271833

17281834
debug(explain) {
17291835
import std.stdio;
@@ -1798,17 +1904,3 @@ mixin template _registerSpecs(alias MODULE)
17981904
}
17991905
}
18001906
}
1801-
1802-
string _declareMethod(string index, ReturnType, string name, ParameterType...)()
1803-
{
1804-
import std.format;
1805-
1806-
enum meth =
1807-
format(`openmethods.Method!("%s", %s, "%s", %s)`,
1808-
index,
1809-
ReturnType.stringof,
1810-
name,
1811-
ParameterType.stringof[1..$-1]);
1812-
return format(`alias %s = %s.dispatcher;`, name, meth)
1813-
~ format(`alias %s = %s.discriminator;`, name, meth);
1814-
}

tests/manualregistration.d

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
}
1414
+/
1515

16+
// EXCLUDE_GDC
17+
1618
static import openmethods;
1719
import openmethods : virtual, declareMethod, defineMethod;
1820

0 commit comments

Comments
 (0)