Re: Manually calling postblots recursively

2017-06-22 Thread Johannes Loher via Digitalmars-d-learn

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
}


Re: Manually calling postblots recursively

2017-06-18 Thread Basile B. via Digitalmars-d-learn

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


Manually calling postblots recursively

2017-06-18 Thread Johannes Loher via Digitalmars-d-learn
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?