Manually calling postblots recursively

Johannes Loher via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Thu Jun 22 01:05:44 PDT 2017


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
}


More information about the Digitalmars-d-learn mailing list