www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Need help to compile code with traits

reply Xavier Bigand <flamaros.xavier gmail.com> writes:
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!(MyClas
).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!(MyClas
).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.
Feb 05
parent reply Basile B. <b2.temp gmx.com> writes:
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!(MyClas
).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!(MyClas
).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.
Feb 05
parent Xavier Bigand <flamaros.xavier gmail.com> writes:
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.
Feb 05