Thread overview | |||||
---|---|---|---|---|---|
|
February 05, 2017 Need help to compile code with traits | ||||
---|---|---|---|---|
| ||||
Hi, I am trying to create an allocator that don't use the GC, and I have issues for the initialization of member before calling the constructor. Here is my actual code : > mixin template NogcAllocator(T) > { > static T nogcNew(T, Args...)(Args args) @nogc > { > import core.stdc.stdlib : malloc; > import std.traits; > > T instance; > > instance = cast(T)malloc(__traits(classInstanceSize, T)); > foreach (string member; __traits(allMembers, T)) > { > static if (isType!(__traits(getMember, T, member))) > __traits(getMember, instance, member) = typeof(__traits(getMember, T, member)).init; > } > > instance.__ctor(args); > return instance; > } > > static void nogcDelete(T)(T instance) @nogc > { > import core.stdc.stdlib : free; > > instance.__dtor(); > free(instance); > } > } > > unittest > { > struct Dummy { > int field1 = 10; > int field2 = 11; > } > > class MyClass { > mixin NogcAllocator!MyClass; > > int a = 0; > int[] b = [1, 2, 3]; > Dummy c = Dummy(4, 5); > > int d = 6; > > this() @nogc { > } > > this(int val) @nogc { > d = val; > } > } > > MyClass first = MyClass.nogcNew!MyClass(); > MyClass second = MyClass.nogcNew!MyClass(7); > > assert(first.a == 0); > assert(first.b == [1, 2, 3]); > assert(first.c.field1 == 4); > assert(first.d == 6); > > assert(second.c.field1 == 4); > assert(second.d == 7); > } And the compilation errors : > ..\src\core\nogc_memory.d(16): Error: no property 'this' for type 'core.nogc_memory.__unittestL39_3.MyClass' > ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression > ..\src\core\nogc_memory.d(63): Error: template instance core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass) error instantiating > ..\src\core\nogc_memory.d(16): Error: no property 'this' for type 'core.nogc_memory.__unittestL39_3.MyClass' > ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression > ..\src\core\nogc_memory.d(64): Error: template instance core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass, int) error instantiating I don't understand my mistake with the getMember and isType traits. And I am curious about of what is the Monitor. |
February 05, 2017 Re: Need help to compile code with traits | ||||
---|---|---|---|---|
| ||||
Posted in reply to Xavier Bigand | On Sunday, 5 February 2017 at 14:59:04 UTC, Xavier Bigand wrote: > Hi, > > I am trying to create an allocator that don't use the GC, and I have issues for the initialization of member before calling the constructor. > Here is my actual code : >> mixin template NogcAllocator(T) >> { >> static T nogcNew(T, Args...)(Args args) @nogc >> { >> import core.stdc.stdlib : malloc; >> import std.traits; >> >> T instance; >> >> instance = cast(T)malloc(__traits(classInstanceSize, T)); >> foreach (string member; __traits(allMembers, T)) >> { >> static if (isType!(__traits(getMember, T, member))) >> __traits(getMember, instance, member) = typeof(__traits(getMember, T, member)).init; >> } >> >> instance.__ctor(args); >> return instance; >> } >> >> static void nogcDelete(T)(T instance) @nogc >> { >> import core.stdc.stdlib : free; >> >> instance.__dtor(); >> free(instance); >> } >> } >> >> unittest >> { >> struct Dummy { >> int field1 = 10; >> int field2 = 11; >> } >> >> class MyClass { >> mixin NogcAllocator!MyClass; >> >> int a = 0; >> int[] b = [1, 2, 3]; >> Dummy c = Dummy(4, 5); >> >> int d = 6; >> >> this() @nogc { >> } >> >> this(int val) @nogc { >> d = val; >> } >> } >> >> MyClass first = MyClass.nogcNew!MyClass(); >> MyClass second = MyClass.nogcNew!MyClass(7); >> >> assert(first.a == 0); >> assert(first.b == [1, 2, 3]); >> assert(first.c.field1 == 4); >> assert(first.d == 6); >> >> assert(second.c.field1 == 4); >> assert(second.d == 7); >> } > > > And the compilation errors : >> ..\src\core\nogc_memory.d(16): Error: no property 'this' for type 'core.nogc_memory.__unittestL39_3.MyClass' >> ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression >> ..\src\core\nogc_memory.d(63): Error: template instance core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass) error instantiating >> ..\src\core\nogc_memory.d(16): Error: no property 'this' for type 'core.nogc_memory.__unittestL39_3.MyClass' >> ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression >> ..\src\core\nogc_memory.d(64): Error: template instance core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass, int) error instantiating > > I don't understand my mistake with the getMember and isType traits. > And I am curious about of what is the Monitor. The whole thing you do to initialize could be replaced by a copy of the initializer, which is what emplace does: static T nogcNew(T, Args...)(Args args) @nogc { import core.stdc.stdlib : malloc; import std.traits, std.meta; T instance; enum s = __traits(classInstanceSize, T); instance = cast(T) malloc(s); (cast(void*) instance)[0..s] = typeid(T).initializer[]; instance.__ctor(args); return instance; } Your nogcDelete() is bug-prone & leaky - use _xdtor, which also calls the __dtor injected by mixin. - even if you do so, __xdtors are not inherited !! instead dtor in parent classes are called by destroy() directly. Currently what I do to simulate inherited destructor is to mix this for each new generation. mixin template inheritedDtor() { private: import std.traits: BaseClassesTuple; alias B = BaseClassesTuple!(typeof(this)); enum hasDtor = __traits(hasMember, typeof(this), "__dtor"); static if (hasDtor && !__traits(isSame, __traits(parent, typeof(this).__dtor), typeof(this))) enum inDtor = true; else enum inDtor = false; public void callInheritedDtor(classT = typeof(this))() { import std.meta: aliasSeqOf; import std.range: iota; foreach(i; aliasSeqOf!(iota(0, B.length))) static if (__traits(hasMember, B[i], "__xdtor")) { mixin("this." ~ B[i].stringof ~ ".__xdtor;"); break; } } static if (!hasDtor || inDtor) public ~this() {callInheritedDtor();} } When a dtor is implemented it has to call "callInheritedDtor()" at end of the dtor implementation. |
February 05, 2017 Re: Need help to compile code with traits | ||||
---|---|---|---|---|
| ||||
Posted in reply to Basile B. | Le 05/02/2017 à 18:32, Basile B. a écrit : > On Sunday, 5 February 2017 at 14:59:04 UTC, Xavier Bigand wrote: >> Hi, >> >> I am trying to create an allocator that don't use the GC, and I have >> issues for the initialization of member before calling the constructor. >> Here is my actual code : >>> mixin template NogcAllocator(T) >>> { >>> static T nogcNew(T, Args...)(Args args) @nogc >>> { >>> import core.stdc.stdlib : malloc; >>> import std.traits; >>> >>> T instance; >>> >>> instance = cast(T)malloc(__traits(classInstanceSize, T)); >>> foreach (string member; __traits(allMembers, T)) >>> { >>> static if (isType!(__traits(getMember, T, member))) >>> __traits(getMember, instance, member) = >>> typeof(__traits(getMember, T, member)).init; >>> } >>> >>> instance.__ctor(args); >>> return instance; >>> } >>> >>> static void nogcDelete(T)(T instance) @nogc >>> { >>> import core.stdc.stdlib : free; >>> >>> instance.__dtor(); >>> free(instance); >>> } >>> } >>> >>> unittest >>> { >>> struct Dummy { >>> int field1 = 10; >>> int field2 = 11; >>> } >>> >>> class MyClass { >>> mixin NogcAllocator!MyClass; >>> >>> int a = 0; >>> int[] b = [1, 2, 3]; >>> Dummy c = Dummy(4, 5); >>> >>> int d = 6; >>> >>> this() @nogc { >>> } >>> >>> this(int val) @nogc { >>> d = val; >>> } >>> } >>> >>> MyClass first = MyClass.nogcNew!MyClass(); >>> MyClass second = MyClass.nogcNew!MyClass(7); >>> >>> assert(first.a == 0); >>> assert(first.b == [1, 2, 3]); >>> assert(first.c.field1 == 4); >>> assert(first.d == 6); >>> >>> assert(second.c.field1 == 4); >>> assert(second.d == 7); >>> } >> >> >> And the compilation errors : >>> ..\src\core\nogc_memory.d(16): Error: no property 'this' for type >>> 'core.nogc_memory.__unittestL39_3.MyClass' >>> ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression >>> ..\src\core\nogc_memory.d(63): Error: template instance >>> core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass) >>> error instantiating >>> ..\src\core\nogc_memory.d(16): Error: no property 'this' for type >>> 'core.nogc_memory.__unittestL39_3.MyClass' >>> ..\src\core\nogc_memory.d(17): Error: type Monitor is not an expression >>> ..\src\core\nogc_memory.d(64): Error: template instance >>> core.nogc_memory.__unittestL39_3.MyClass.NogcAllocator!(MyClass).nogcNew!(MyClass, >>> int) error instantiating >> >> I don't understand my mistake with the getMember and isType traits. >> And I am curious about of what is the Monitor. > > The whole thing you do to initialize could be replaced by a copy of the > initializer, which is what emplace does: > > > static T nogcNew(T, Args...)(Args args) @nogc > { > import core.stdc.stdlib : malloc; > import std.traits, std.meta; > > T instance; > enum s = __traits(classInstanceSize, T); > > instance = cast(T) malloc(s); > (cast(void*) instance)[0..s] = typeid(T).initializer[]; > > instance.__ctor(args); > return instance; > } > Nice, thank you for that, it is much elegant ;-) > > Your nogcDelete() is bug-prone & leaky Certainly I didn't think a lot about it for the moment. > > - use _xdtor, which also calls the __dtor injected by mixin. > - even if you do so, __xdtors are not inherited !! instead dtor in > parent classes are called by destroy() directly. > > Currently what I do to simulate inherited destructor is to mix this for > each new generation. > > mixin template inheritedDtor() > { > > private: > > import std.traits: BaseClassesTuple; > > alias B = BaseClassesTuple!(typeof(this)); > enum hasDtor = __traits(hasMember, typeof(this), "__dtor"); > static if (hasDtor && !__traits(isSame, __traits(parent, > typeof(this).__dtor), typeof(this))) > enum inDtor = true; > else > enum inDtor = false; > > public void callInheritedDtor(classT = typeof(this))() > { > import std.meta: aliasSeqOf; > import std.range: iota; > > foreach(i; aliasSeqOf!(iota(0, B.length))) > static if (__traits(hasMember, B[i], "__xdtor")) > { > mixin("this." ~ B[i].stringof ~ ".__xdtor;"); > break; > } > } > > static if (!hasDtor || inDtor) > public ~this() {callInheritedDtor();} > } > > When a dtor is implemented it has to call "callInheritedDtor()" at end > of the dtor implementation. Thank you a lot for this great help. |
Copyright © 1999-2021 by the D Language Foundation