www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D hackers requested. Dancing around postblit.

reply "IgorStepanov" <wazar mail.ru> writes:
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.)
Nov 05 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Nov 05 2014
parent reply "IgorStepanov" <wazar mail.ru> writes:
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.
Nov 05 2014
next sibling parent "IgorStepanov" <wazar mail.ru> writes:
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.
Nov 05 2014
prev sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
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.
Nov 05 2014
parent "IgorStepanov" <wazar mail.ru> writes:
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.
Nov 05 2014