On Sunday, 18 June 2017 at 14:16:03 UTC, Basile B. wrote:
On Sunday, 18 June 2017 at 09:41:01 UTC, Johannes Loher wrote:
Hey, I'm trying to work on https://issues.dlang.org/show_bug.cgi?id=15708 so I decided it might be interesting to find a way to (recursively) call all postblits that belong to certain struct or static array. This is what I came up with so far:

[...]

"@disable" postblits are detected as valid postblits.
I think that you have to AndAnd the detection with std.traits.isCopyable

Here is my new version. Additionally to taking care of @disable this(this); I added compile time checks if the underlying fields have an "elaborate copy constructor" so that I only call callPostblits on them if needed. Is this reasonable? It increases compiletime, but could possibly decrease runtime a little. On the other hand, the empty function calls should probably just get optimized away...?

While doing all that I realized that hasElaborateCopyConstructor is true for structs with @disable this(this). Is that intended? It looks a bit weird to me...



import std.traits;

void callPostblits(S)(ref S s)
{
static if (isStaticArray!S && S.length && hasElaborateCopyConstructor!(ElementType!S))
    {
        foreach (ref elem; s)
            callPostblits(elem);
    }
    else static if (is(S == struct))
    {
        foreach (field; FieldNameTuple!S)
        {
static if (hasElaborateCopyConstructor!(typeof(__traits(getMember, s, field))))
            {
                callPostblits(__traits(getMember, s, field));
            }
        }

        static if (hasMember!(S, "__postblit") && isCopyable!S)
        {
            s.__postblit();
        }
    }
}

unittest
{

    struct AnotherTestStruct
    {
        int b = 0;

        this(this)
        {
            b = 1;
        }
    }

    struct TestStruct
    {
        int a = 0;

        this(this)
        {
            a = 1;
        }

        AnotherTestStruct anotherTestStruct;
    }


    TestStruct[2] testStructs;

assert(testStructs[0].a == 0 && testStructs[0].anotherTestStruct.b == 0); assert(testStructs[1].a == 0 && testStructs[1].anotherTestStruct.b == 0);

    callPostblits(testStructs);

assert(testStructs[0].a == 1 && testStructs[0].anotherTestStruct.b == 1); assert(testStructs[1].a == 1 && testStructs[1].anotherTestStruct.b == 1);

    struct YetAnotherTestStruct
    {
        @disable this(this);
    }

    YetAnotherTestStruct yetAnotherTestStruct;
    callPostblits(yetAnotherTestStruct); // This will also compile
}

Reply via email to