Thread overview
D hackers requested. Dancing around postblit.
Nov 05, 2014
IgorStepanov
Nov 05, 2014
Adam D. Ruppe
Nov 05, 2014
IgorStepanov
Nov 05, 2014
IgorStepanov
Nov 05, 2014
Adam D. Ruppe
Nov 05, 2014
IgorStepanov
November 05, 2014
Please try to solve this task:
We have a struct S.
S has a some kind of postblit (user-defined or inherited frome field) and destructor. S has a @disabled opAssign.
We have an unitialized allocated memory block whick mapped to a S array.
struct S
{
   //postblit and dtor here
}
S[] data; // contains a garbarge

void emplace()(ref S val, size_t i);

The task: we should write emplace function, which initializes i-th element of data with val;
This function shouldn't call any dtors for example for the old data[i] (which contains a garbarge).
This function should be transparent for attributes. For example, if S postblit is nothrow emplace should be nothrow too. If S postblit is not nothrow, S should't be nothrow.
This function should call postblit only one time and shouldn't call any other S special functions (opAssign, ctor etc.)
November 05, 2014
If you're willing to make it @system or @trusted, you can just copy the data and call postblit manually:

extern(C) @safe int printf(in char*);

struct S {
        ~this() { printf("dtor\n"); }
        this(this) { printf("postblit\n"); }

        @disable S opAssign(S s);
}

S[] data;
void emplace(Struct)(ref Struct val, size_t i) {
        // just blit the struct contents over
        // (same thing normal assign does anyway)
        (cast(ubyte*)&(data[i]))[0 .. Struct.sizeof] = (cast(ubyte*)&val)[0 ..  Struct.sizeof];
        // call postblit
        data[i].__postblit();
}

void main() {
        data.length = 1;
        S s;

        emplace(s, 0);
}



Since it is a template, attribute inference should take care of nothrow, etc.
November 05, 2014
On Wednesday, 5 November 2014 at 20:01:59 UTC, Adam D. Ruppe wrote:
> If you're willing to make it @system or @trusted, you can just copy the data and call postblit manually:
>
> extern(C) @safe int printf(in char*);
>
> struct S {
>         ~this() { printf("dtor\n"); }
>         this(this) { printf("postblit\n"); }
>
>         @disable S opAssign(S s);
> }
>
> S[] data;
> void emplace(Struct)(ref Struct val, size_t i) {
>         // just blit the struct contents over
>         // (same thing normal assign does anyway)
>         (cast(ubyte*)&(data[i]))[0 .. Struct.sizeof] = (cast(ubyte*)&val)[0 ..  Struct.sizeof];
>         // call postblit
>         data[i].__postblit();
> }
>
> void main() {
>         data.length = 1;
>         S s;
>
>         emplace(s, 0);
> }
>
>
>
> Since it is a template, attribute inference should take care of nothrow, etc.

It was my first try :(
data[i].__postblit();
calls the user-defined postblit and only it.

struct Sx {
         ~this() { printf("dtor\n"); }
         this(this) { printf("postblit\n"); }

         @disable S opAssign(S s);
}

struct S
{
   Sx s;
}

data[i].__postblit(); //error: S hasn't __postblit member, but it need the postblit call for Sx
typeid(S).postblit(&data[i]) works as needed, but doesn't save postblit attributes.
November 05, 2014
FYI:
My second try:

void emplace(V1)(ref V1 dst, ref V1 src) @trusted if (is(V1 == struct))
{
    static if (new_obj)
    {
        V1 tmp = cast(V1)src; //create copy and call postblit
        static V1 init = V1.init;
        //bitwise copy of object, which already postblitted
        (cast(void*)&dst)[0 .. V1.sizeof] = (cast(void*)&tmp)[0 .. V1.sizeof];

        //initialize tmp with V1.init.
        (cast(void*)&tmp)[0 .. V1.sizeof] = (cast(void*)&init)[0 .. V1.sizeof];
    }
}

This method do one extra dtor call for tmp, but it may be trivial because tmp is V.init.
However it is not a complete solution of the task.
November 05, 2014
On Wednesday, 5 November 2014 at 20:19:03 UTC, IgorStepanov wrote:
> data[i].__postblit(); //error: S hasn't __postblit member, but it need the postblit call for Sx

Hmm, we could perhaps do a recursive call with __traits(allMembers) and if it has a __postblit.
November 05, 2014
On Wednesday, 5 November 2014 at 20:33:40 UTC, Adam D. Ruppe wrote:
> On Wednesday, 5 November 2014 at 20:19:03 UTC, IgorStepanov wrote:
>> data[i].__postblit(); //error: S hasn't __postblit member, but it need the postblit call for Sx
>
> Hmm, we could perhaps do a recursive call with __traits(allMembers) and if it has a __postblit.

Good point. I'll try it. Thanks.