www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Manually calling postblots recursively

reply Johannes Loher <johannes.loher fg4f.de> writes:
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:

import std.traits;

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

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

 safe 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);
}

Any suggestions for improvement or cases where this fails?
Jun 18 2017
parent reply Basile B. <b2.temp gmx.com> writes:
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
Jun 18 2017
parent Johannes Loher <johannes.loher fg4f.de> writes:
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 }
Jun 22 2017