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.

Reply via email to