1 /*
2     TODO
3 
4     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
5     Authors:   Adam Búš
6 */
7 module btl.lifetime;
8 
9 
10 import std.meta : AliasSeq;
11 
12 import core.lifetime : forward, move;
13 import std.range : isInputRange, ElementEncodingType;
14 import std.traits : isDynamicArray;
15 
16 import btl.traits.range : isBtlInputRange;
17 
18 /*
19     Type used as parameter for function pointer returned from `DestructorType`.
20 */
21 public struct Evoid{
22 
23 }
24 
25 //generate `DestructorTypes` alias
26 /+version(D_BetterC){}else
27 private string genDestructorTypes(){
28     string result;
29     result.reserve(16*40);
30 
31     import std.range : empty;
32     foreach(string _pure; ["pure", ""])
33     foreach(string _nothrow; ["nothrow", ""])
34     foreach(string _safe; ["@safe", "@system"])
35     foreach(string _nogc; ["@nogc", ""])
36         result ~= "void function(void* )" ~ _pure
37             ~ (_pure.empty?"":" ") ~ _nothrow
38             ~ ((_pure.empty && _nothrow.empty)?"":" ") ~ _safe
39             ~ ((_pure.empty && _nothrow.empty && _safe.empty)?"":" ") ~ _nogc
40             ~ ",\n";
41 
42     return result;
43 }+/
44 
45 
46 //create all possible DestructorType types, DestructorType can return type with some hidden information and comparsion with it can fail (bug in D compiler).
47 //If type is created before calling DestructorType then DestructorType return existing type free of hidden informations and comparsion is ok.
48 public alias DtorTypes = AliasSeq!(
49     void function(Evoid* )pure nothrow @safe @nogc,
50     void function(Evoid* )pure nothrow @safe,
51     void function(Evoid* )pure nothrow @system @nogc,
52     void function(Evoid* )pure nothrow @system,
53     void function(Evoid* )pure @safe @nogc,
54     void function(Evoid* )pure @safe,
55     void function(Evoid* )pure @system @nogc,
56     void function(Evoid* )pure @system,
57     void function(Evoid* )nothrow @safe @nogc,
58     void function(Evoid* )nothrow @safe,
59     void function(Evoid* )nothrow @system @nogc,
60     void function(Evoid* )nothrow @system,
61     void function(Evoid* )@safe @nogc,
62     void function(Evoid* )@safe,
63     void function(Evoid* )@system @nogc,
64     void function(Evoid* )@system,
65 );
66 
67 
68 
69 /*
70     Check if type `Type` is of type destructor type (is(void function(Evoid* )pure nothrow @safe @nogc : Type))
71 */
72 public template isDtorType(Type){
73     enum bool isDtorType = is(
74         void function(Evoid* )pure nothrow @safe @nogc : Type
75     );
76 }
77 
78 //
79 unittest{
80     static assert(isDtorType!(void function(Evoid* )pure));
81     static assert(isDtorType!(DtorType!long));
82     static assert(!isDtorType!(long));
83 }
84 
85 
86 
87 public template ClassDtorType(Type)
88 if(is(Type == class)){
89     import std.traits : Unqual, BaseClassesTuple;
90     import std.meta : AliasSeq;
91 
92     alias Get(T) = T;
93     static void impl()(Evoid*){
94         // generate a body that calls all the destructors in the chain,
95         // compiler should infer the intersection of attributes
96         foreach (B; AliasSeq!(Type, BaseClassesTuple!Type)) {
97             alias UB = Unqual!B;
98 
99             // __dtor, i.e. B.~this
100             static if (__traits(hasMember, B, "__dtor"))
101                 () { UB obj; obj.__dtor; } ();
102             // __xdtor, i.e. dtors for all RAII members
103             static if (__traits(hasMember, B, "__xdtor"))
104                 () { UB obj; obj.__xdtor; } ();
105         }
106     }
107 
108     alias ClassDtorType = Get!(typeof(&impl!()));
109 }
110 
111 public template DtorType(Type){
112 
113     import std.traits : Unqual, isDynamicArray, BaseClassesTuple;
114     import std.range : ElementEncodingType;
115     import std.meta : AliasSeq;
116 
117     alias Get(T) = T;
118     static void impl()(Evoid*){
119         static if(is(Unqual!Type == void)){
120             //nothing
121         }
122         else static if(is(Type == interface) || is(Type == class)){
123             //nothing
124         }
125         else{
126             Unqual!Type tmp;
127         }
128     }
129 
130     alias DtorType = Get!(typeof(&impl!()));
131 }
132 
133 
134 
135 //emplaceImpl & emplaceRangeImpl & emplaceClassImpl
136 public{
137     void emplaceImpl(T, Args...)(ref T elm, auto ref Args args){
138         static if(is(T == class) || is(T == interface)){
139             import std.traits : Unqual;
140 
141             static if(Args.length == 0){
142                 *(()@trusted => cast(Unqual!T*)&elm )() = null;
143             }
144             else static if(Args.length == 1 && is(Args[0] : T)){
145                 T src = args[0];
146 
147                 ()@trusted{
148                     *cast(Unqual!T*)&elm = cast(Unqual!T)src;
149                 }();
150             }
151             else{
152                 static assert(0, "cannot emplace class with parameters " ~ args.stringof ~ ", try emplaceClassImpl instead");
153             }
154         }
155         else{
156             import core.lifetime : forward;
157             import core.internal.lifetime : emplaceRef;
158 
159             emplaceRef!T(elm, forward!args);
160         }
161     }
162 
163     void emplaceImpl(T, S)(ref T elm, return ref S src)
164     if(is(T == struct) && is(S == struct) && is(immutable T == immutable S)){
165         import core.internal.lifetime : emplaceRef;
166 
167         emplaceRef!T(elm, src);
168 
169     }
170 
171     void emplaceRangeImpl(T, Args...)(T[] slice, auto ref Args args){
172         foreach(ref elm; slice)
173             emplaceImpl(elm, args);
174 
175     }
176 
177     void emplaceClassImpl(T, Args...)(T elm, auto ref Args args)
178     if(is(T == class)){
179         import core.lifetime : forward, emplace;
180 
181         emplace(elm, forward!args);
182     }
183 }
184 
185 //destructImpl & destructRangeImpl & destructClassImpl
186 public{
187     //destructImpl:
188     void destructImpl(bool initialize = false, T)(ref T obj){
189         destructImpl!(initialize, DtorType!T)(obj);
190     }
191     void destructImpl(bool initialize, DestructorType, T)(ref T obj)
192     if(isDtorType!DestructorType){
193         import std.traits : Unqual;
194         import btl.traits.assume;
195 
196         if(false){
197             DestructorType dt;
198             dt(null);
199         }
200         Unqual!T* mutableObj = (()@trusted => cast(Unqual!T*)&obj )();
201 
202         static if(is(T == class) || is(T == interface)){
203             static if(initialize)
204                 *mutableObj = null;
205         }
206         else{
207             assumePureNoGcNothrow((Unqual!T* o)@trusted{
208                 destroy!initialize(*o);
209             })(mutableObj);
210         }
211     }
212 
213 
214     //destructRangeImpl:
215     void destructRangeImpl(bool initialize = false, T)(T[] slice){
216         destructRangeImpl!(initialize, DtorType!T)(slice);
217 
218     }
219     void destructRangeImpl(bool initialize, DestructorType, T)(T[] slice)
220     if(isDtorType!DestructorType){
221 
222         static if(is(T == void)){
223             if(false){
224                 DestructorType dt;
225                 dt(null);
226             }
227 
228             static if(initialize){} //TODO
229         }
230         else{
231             foreach(ref elm; slice)
232                 destructImpl!(initialize, DestructorType, T)(elm);
233 
234         }
235     }
236 
237 
238     //class destructor
239     private extern(C) void rt_finalize2(void* p, bool det = true, bool resetMemory = false)nothrow @safe @nogc pure;
240 
241     //destructClassImpl:
242     void destructClassImpl(bool initialize, DestructorType, T)(T obj)
243     if(is(T == class) && isDtorType!DestructorType){
244         import std.traits : Unqual;
245         import btl.traits.assume;
246 
247         if(false){
248             DestructorType dt;
249             dt(null);
250         }
251 
252         ///C++ class
253         static if (__traits(getLinkage, T) == "C++"){
254             Unqual!T mutableObj = (()@trusted => cast(Unqual!T)obj )();
255 
256             assumePureNoGcNothrow((Unqual!T o)@trusted{
257                 destroy!initialize(o);
258             })(mutableObj);
259         }
260         ///D class
261         static if(__traits(getLinkage, T) == "D"){
262 
263             assumePureNoGcNothrow((T o)@trusted{
264                 //resetMemory must be false because intrusiv pointers can contains control block with weak references.
265                 rt_finalize2(cast(void*)o, true, initialize);
266             })(obj);
267         }
268         else static assert(0, "no impl");
269     }
270     void destructClassImpl(bool initialize = false, T)(T obj)
271     if(is(T == class)){
272         destructClassImpl!(initialize, ClassDtorType!T)(obj);
273     }
274 }
275 
276 //transferEmplaceImpl
277 private{
278     void transferEmplaceImpl(bool move, S, T)(scope ref T target, return scope ref S source)
279     if(is(immutable S == immutable T)){
280         static if(move)
281             moveEmplaceImpl(target, source);
282         else
283             copyEmplaceImpl(target, source);
284     }
285 
286     void transferEmplaceImpl(bool move, S, T)(scope ref T target, return scope ref S source)
287     if(!is(immutable S == immutable T) && is(immutable S : immutable T)){
288         import std.range : ElementEncodingType;
289         import std.traits :
290             CopyTypeQualifiers, Unqual,
291             isDynamicArray, isStaticArray,
292             isPointer, PointerTarget,
293             isFunctionPointer, isDelegate;
294 
295 
296         static if(is(S == struct) || is(S == union)){
297             transferEmplaceImpl!(move, CopyTypeQualifiers!(S, Unqual!T), T)(target, source);
298         }
299         else static if(isStaticArray!S){
300             static if(S.length){
301                 transferEmplaceRangeImpl!move(
302                     (()@trusted => target.ptr )(),
303                     (()@trusted => source.ptr )(),
304                     T.length
305                 );
306             }
307         }
308         else static if(is(S == class) || is(S == interface)){
309             CopyTypeQualifiers!(S, Unqual!T) src = source;
310             transferEmplaceImpl!move(target, src);
311         }
312         else static if(isDynamicArray!S){
313             auto src = ()@trusted{
314                 return cast(CopyTypeQualifiers!(ElementEncodingType!S, Unqual!(ElementEncodingType!T))[] )source;
315             }();
316             transferEmplaceImpl!move(target, src);
317         }
318         else static if(isPointer!S){
319             auto src = ()@trusted{
320                 return cast(CopyTypeQualifiers!(PointerTarget!S, Unqual!(PointerTarget!T))* )source;
321             }();
322             transferEmplaceImpl!move(target, src);
323         }
324         else{
325             CopyTypeQualifiers!(S, Unqual!T) src = source;
326             transferEmplaceImpl!move(target, src);
327         }
328     }
329 
330     void transferEmplaceRangeImpl(bool move, S, T)(T* target, S* source, size_t length)
331     if(is(immutable S[] : immutable T[])){
332         static if(move)
333             moveEmplaceRangeImpl!false(target, source, length);
334         else
335             copyEmplaceRangeImpl(target, source, length);
336 
337 
338     }
339 
340     void transferAssignRangeImpl(bool move, S, T)(T* target, S* source, size_t length)
341     if(is(immutable S[] : immutable T[])){
342         import std.traits : Unqual, hasElaborateAssign;
343 
344         if(length == 0)
345             return;
346 
347         static if (hasElaborateAssign!T){
348             for (size_t i = 0; i < length; i++){
349                 static if(move)
350                     *(()@trusted => target + i )() = .move(*(()@trusted => source + i )());
351                 else
352                     *(()@trusted => target + i )() = *(()@trusted => source + i )();
353 
354             }
355         }
356         else // trivial copy
357         {
358             static assert(T.sizeof == S.sizeof);
359 
360             () @trusted{
361                 import core.stdc.string : memcpy;
362 
363                 memcpy(
364                     cast(Unqual!T*) target,
365                     cast(Unqual!T*) source,
366                     T.sizeof * length
367                 );
368             }();
369         }
370     }
371 
372     void transferAssignRange(bool move, T, S)(T[] target, ref S[] source){
373         import btl.internal.traits : min;
374 
375         assert(target.length <= source.length);
376 
377         transferAssignRangeImpl!move(
378             (()@trusted => target.ptr )(),
379             (()@trusted => source.ptr )(),
380             target.length//min(target.length, source.length)
381         );
382     }
383 
384     void transferAssignRange(bool move, T, R)(T[] target, ref R source)
385     if(isBtlInputRange!R && is(immutable ElementEncodingType!R[] : immutable T[]) && !isDynamicArray!R){
386         import std.range ; popFront;
387         import core.lifetime : mv = move;
388 
389         foreach(ref elm; target){
390             assert(!source.empty);
391 
392             static if(move)
393                 elm = mv(source.front);
394             else
395                 elm = source.front;
396 
397             source.popFront;
398         }
399     }
400 }
401 
402 //moveEmplaceImpl
403 public{
404     // https://github.com/dlang/druntime/blob/master/src/core/lifetime.d : moveEmplaceImpl
405     // target must be first-parameter, because in void-functions DMD + dip1000 allows it to take the place of a return-scope
406     void moveEmplaceImpl(S, T)(scope ref T target, return scope ref S source)
407     if(is(immutable S == immutable T)){
408         // TODO: this assert pulls in half of phobos. we need to work out an alternative assert strategy.
409     //    static if (!is(T == class) && hasAliasing!T) if (!__ctfe)
410     //    {
411     //        import std.exception : doesPointTo;
412     //        assert(!doesPointTo(source, source) && !hasElaborateMove!T),
413     //              "Cannot move object with internal pointer unless `opPostMove` is defined.");
414     //    }
415 
416         import core.internal.traits : hasElaborateAssign, isAssignable, hasElaborateMove,
417                                       hasElaborateDestructor, hasElaborateCopyConstructor, Unqual;
418 
419         Unqual!T* mutableTarget = (()@trusted => cast(Unqual!T*)&target )();
420         Unqual!S* mutableSource = (()@trusted => cast(Unqual!S*)&source )();
421 
422         static if (is(T == struct))
423         {
424 
425             //  Unsafe when compiling without -preview=dip1000
426             assert((() @trusted => &source !is &target)(), "source and target must not be identical");
427 
428 
429 
430             static if (hasElaborateAssign!T || !isAssignable!T)
431             {
432                 import core.stdc.string : memcpy;
433                 () @trusted{
434                     memcpy(
435                         mutableTarget,
436                         mutableSource,
437                         T.sizeof
438                     );
439                 }();
440             }
441             else
442                 *mutableTarget = *mutableSource;
443 
444             static if (hasElaborateMove!T)
445                 __move_post_blt(target, source);
446 
447             // If the source defines a destructor or a postblit hook, we must obliterate the
448             // object in order to avoid double freeing and undue aliasing
449             static if (hasElaborateDestructor!T || hasElaborateCopyConstructor!T)
450             {
451                 // If there are members that are nested structs, we must take care
452                 // not to erase any context pointers, so we might have to recurse
453                 static if (__traits(isZeroInit, T))
454                     wipe(source);
455                 else
456                     wipe(source, ref () @trusted { return *cast(immutable(T)*) __traits(initSymbol, T).ptr; } ());
457             }
458         }
459         else static if (__traits(isStaticArray, T))
460         {
461             static if (T.length)
462             {
463                 /+moveEmplaceRangeImpl!false(
464                     (()@trusted => target.ptr )(),
465                     (()@trusted => source.ptr )(),
466                     T.length
467                 );+/
468                 static if (!hasElaborateMove!T &&
469                            !hasElaborateDestructor!T &&
470                            !hasElaborateCopyConstructor!T)
471                 {
472                     // Single blit if no special per-instance handling is required
473                     () @trusted
474                     {
475                         assert(source.ptr !is target.ptr, "source and target must not be identical");
476                         *cast(ubyte[T.sizeof]*) &target = *cast(ubyte[T.sizeof]*) &source;
477                     } ();
478                 }
479                 else
480                 {
481                     for (size_t i = 0; i < source.length; ++i)
482                         moveEmplaceImpl(target[i], source[i]);
483                 }
484 
485             }
486         }
487         else
488         {
489             // Primitive data (including pointers and arrays) or class -
490             // assignment works great
491             static if(is(S : T)){
492 
493                 *mutableTarget = *mutableSource;
494 
495             }
496             else
497                 static assert(0, "no impl");
498         }
499     }
500 
501     void moveEmplaceImpl(S, T)(scope ref T target, return scope ref S source)
502     if(!is(immutable S == immutable T) && is(immutable S : immutable T)){
503         transferEmplaceImpl!true(target, source);
504     }
505 
506     void moveEmplaceRangeImpl(bool overlap = true, S, T)(T* target, S* source, size_t length)
507     if(is(immutable S[] : immutable T[])){
508         import std.traits : hasElaborateMove, hasElaborateDestructor, hasElaborateCopyConstructor, Unqual;
509 
510         if(length == 0)
511             return;
512 
513         static if(is(immutable S* : immutable T*)
514             && !hasElaborateMove!T
515             && !hasElaborateDestructor!T
516             && !hasElaborateCopyConstructor!T
517         ){
518             // Single blit if no special per-instance handling is required
519             /+() @trusted{
520                 assert(source.ptr !is target.ptr, "source and target must not be identical");
521                 *cast(ubyte[T.sizeof]*) target = *cast(ubyte[T.sizeof]*) source;
522             }();+/
523 
524             static assert(T.sizeof == S.sizeof);
525 
526             () @trusted{
527                 import core.stdc.string : memcpy, memmove;
528                 static if(overlap)
529                     memmove(
530                         cast(Unqual!T*) target,
531                         cast(Unqual!T*) source,
532                         T.sizeof * length
533                     );
534                 else
535                     memcpy(
536                         cast(Unqual!T*) target,
537                         cast(Unqual!T*) source,
538                         T.sizeof * length
539                     );
540             }();
541         }
542         else{
543 
544             if(!overlap || target < source){
545                 for(size_t i = 0; i < length; ++i){
546                     //moveEmplace(source[i], target[i]);
547                     moveEmplaceImpl(
548                         *(()@trusted => target + i )(),
549                         *(()@trusted => source + i )()
550                     );
551                 }
552             }
553             else{
554                 size_t i = length;
555                 do{
556                     i -= 1;
557                     moveEmplaceImpl(
558                         *(()@trusted => target + i )(),
559                         *(()@trusted => source + i )()
560                     );
561 
562                 }while(i > 0);
563             }
564         }
565 
566     }
567 
568     void moveAssignRangeImpl(S, T)(T* target, S* source, size_t length)
569     if(is(immutable S[] : immutable T[])){
570         transferAssignRangeImpl!true(target, source, length);
571     }
572 
573     void moveAssignRange(T, R)(T[] target, ref R source)
574     if(isBtlInputRange!R && is(immutable ElementEncodingType!R[] : immutable T[])){
575         transferAssignRange!true(target, source);
576     }
577 
578     @safe pure nothrow @nogc unittest{
579         {
580             const int trg;
581             int src;
582             moveEmplaceImpl(trg, src);
583         }
584         {
585             const long trg;
586             int src;
587             moveEmplaceImpl(trg, src);
588         }
589         {
590             const int* trg;
591             int* src;
592             moveEmplaceImpl(trg, src);
593         }
594         {
595             const int* trg;
596             int* src;
597             moveEmplaceImpl(trg, src);
598         }
599         {
600             struct S{
601                 void* p;
602                 int i;
603             }
604             const S trg;
605             S src;
606             moveEmplaceImpl(trg, src);
607         }
608         {
609             struct S{
610                 void* p;
611                 int i;
612                 ~this(){}
613             }
614             const S trg;
615             S src;
616             moveEmplaceImpl(trg, src);
617         }
618         {
619             struct S{
620                 void* p;
621                 int i;
622                 ~this(){}
623             }
624             const S[4] trg;
625             S[4] src;
626             moveEmplaceImpl(trg, src);
627         }
628         {
629             static class B{}
630             static class D : B{}
631             {
632                 const B trg;
633                 D src;
634                 moveEmplaceImpl(trg, src);
635             }
636             {
637                 const B[] trg;
638                 D[] src;
639                 moveEmplaceImpl(trg, src);
640             }
641             {
642                 const B* trg;
643                 D* src;
644                 moveEmplaceImpl(trg, src);
645             }
646             {
647                 const B[4] trg;
648                 D[4] src;
649                 moveEmplaceImpl(trg, src);
650             }
651         }
652 
653         {
654             void delegate()@system trg;
655             void delegate()@safe src;
656             moveEmplaceImpl(trg, src);
657 
658         }
659 
660     }
661 
662     // https://github.com/dlang/druntime/blob/master/src/core/lifetime.d : wipe
663     // wipes source after moving
664     pragma(inline, true)
665     private void wipe(T, Init...)(return scope ref T source, ref const scope Init initializer) @trusted
666     if (!Init.length ||
667         ((Init.length == 1) && (is(immutable T == immutable Init[0]))))
668     {
669         static if (__traits(isStaticArray, T) && hasContextPointers!T)
670         {
671             for (auto i = 0; i < T.length; i++)
672                 static if (Init.length)
673                     wipe(source[i], initializer[0][i]);
674                 else
675                     wipe(source[i]);
676         }
677         else static if (is(T == struct) && hasContextPointers!T)
678         {
679             import core.internal.traits : anySatisfy;
680             static if (anySatisfy!(hasContextPointers, typeof(T.tupleof)))
681             {
682                 static foreach (i; 0 .. T.tupleof.length - __traits(isNested, T))
683                     static if (Init.length)
684                         wipe(source.tupleof[i], initializer[0].tupleof[i]);
685                     else
686                         wipe(source.tupleof[i]);
687             }
688             else
689             {
690                 static if (__traits(isNested, T))
691                     enum sz = T.tupleof[$-1].offsetof;
692                 else
693                     enum sz = T.sizeof;
694 
695                 static if (Init.length)
696                     *cast(ubyte[sz]*) &source = *cast(ubyte[sz]*) &initializer[0];
697                 else
698                     *cast(ubyte[sz]*) &source = 0;
699             }
700         }
701         else
702         {
703             import core.internal.traits : hasElaborateAssign, isAssignable;
704             static if (Init.length)
705             {
706                 static if (hasElaborateAssign!T || !isAssignable!T)
707                     *cast(ubyte[T.sizeof]*) &source = *cast(ubyte[T.sizeof]*) &initializer[0];
708                 else
709                     source = *cast(T*) &initializer[0];
710             }
711             else
712             {
713                 *cast(ubyte[T.sizeof]*) &source = 0;
714             }
715         }
716     }
717 
718     // https://github.com/dlang/druntime/blob/master/src/core/lifetime.d : hasContextPointers
719     private enum bool hasContextPointers(T) = {
720         static if (__traits(isStaticArray, T))
721         {
722             return hasContextPointers!(typeof(T.init[0]));
723         }
724         else static if (is(T == struct))
725         {
726             import core.internal.traits : anySatisfy;
727             return __traits(isNested, T) || anySatisfy!(hasContextPointers, typeof(T.tupleof));
728         }
729         else return false;
730     } ();
731 }
732 
733 //copyEmplaceImpl
734 public{
735     // https://github.com/dlang/druntime/blob/master/src/core/lifetime.d : copyEmplace
736     void copyEmplaceImpl(S, T)(ref T target, return auto ref S source)
737     if (is(immutable S == immutable T)){
738         emplaceImpl(target, source);
739         /+import core.internal.traits : BaseElemOf, hasElaborateCopyConstructor, Unconst, Unqual;
740 
741         // cannot have the following as simple template constraint due to nested-struct special case...
742         static if (!__traits(compiles, (ref S src) { T tgt = src; }))
743         {
744             alias B = BaseElemOf!T;
745             enum isNestedStruct = is(B == struct) && __traits(isNested, B);
746             static assert(isNestedStruct, "cannot copy-construct " ~ T.stringof ~ " from " ~ S.stringof);
747         }
748 
749         Unqual!T* mutableTarget = (()@trusted => cast(Unqual!T*)&target )();
750         Unqual!S* mutableSource = (()@trusted => cast(Unqual!S*)&source )();
751 
752         void blit()
753         {
754             import core.stdc.string : memcpy;
755             ()@trusted{
756                 memcpy(mutableTarget, mutableSource, T.sizeof);
757             }();
758         }
759 
760         static if (is(T == struct))
761         {
762             static if (__traits(hasPostblit, T))
763             {
764                 blit();
765                 (cast() target).__xpostblit();
766             }
767             else static if (__traits(hasCopyConstructor, T))
768             {
769                 emplace(cast(Unqual!(T)*) &target); // blit T.init
770                 static if (__traits(isNested, T))
771                 {
772                      // copy context pointer
773                     *(cast(void**) &target.tupleof[$-1]) = cast(void*) source.tupleof[$-1];
774                 }
775                 target.__ctor(source); // invoke copy ctor
776             }
777             else
778             {
779                 blit(); // no opAssign
780             }
781         }
782         else static if (is(T == E[n], E, size_t n))
783         {
784             static if(n){
785                 copyEmplaceRangeImpl(
786                     (()@trusted => target.ptr )(),
787                     (()@trusted => source.ptr )(),
788                     T.length
789                 );
790             }
791             /+static if (hasElaborateCopyConstructor!E)
792             {
793                 size_t i;
794                 scope(failure){
795                     // destroy, in reverse order, what we've constructed so far
796                     while (i--)
797                         destroy(*cast(Unconst!(E)*) &target[i]);
798 
799                 }
800                 for (i = 0; i < n; i++)
801                     copyEmplaceImpl(target[i], source[i]);
802             }
803             else // trivial copy
804             {
805                 blit(); // all elements at once
806             }+/
807         }
808         else
809         {
810             *mutableTarget = *mutableSource;
811         }+/
812     }
813 
814     void copyEmplaceImpl(S, T)(ref T target, return ref S source)
815     if(!is(immutable S == immutable T) && is(immutable S : immutable T)){
816         transferEmplaceImpl!false(target, source);
817     }
818 
819     void copyEmplaceRangeImpl(S, T)(T* target, S* source, size_t length)
820     if(is(immutable S[] : immutable T[])){
821         import std.traits : Unqual, hasElaborateCopyConstructor;
822 
823         if(length == 0)
824             return;
825 
826         static if (hasElaborateCopyConstructor!T){
827             size_t i;
828             scope(failure){
829                 // destroy, in reverse order, what we've constructed so far
830                 while (i--)
831                     destroy(*cast(Unconst!T*) &target[i]);
832 
833             }
834             for (i = 0; i < length; i++)
835                 copyEmplaceImpl(
836                     *(()@trusted => target + i )(),
837                     *(()@trusted => source + i )()
838                 );
839         }
840         else // trivial copy
841         {
842             static assert(T.sizeof == S.sizeof);
843 
844             () @trusted{
845                 import core.stdc.string : memcpy;
846 
847                 memcpy(
848                     cast(Unqual!T*) target,
849                     cast(Unqual!T*) source,
850                     T.sizeof * length
851                 );
852             }();
853         }
854     }
855 
856     void copyAssignRangeImpl(S, T)(T* target, S* source, size_t length)
857     if(is(immutable S[] : immutable T[])){
858         transferAssignRangeImpl!false(target, source, length);
859     }
860 
861     void copyAssignRange(T, R)(T[] target, ref R source)
862     if(isBtlInputRange!R && is(immutable ElementEncodingType!R[] : immutable T[])){
863         transferAssignRange!false(target, source);
864     }
865 
866     @safe pure nothrow @nogc unittest{
867         {
868             const int trg;
869             int src;
870             copyEmplaceImpl(trg, src);
871         }
872         {
873             const long trg;
874             int src;
875             copyEmplaceImpl(trg, src);
876         }
877         {
878             const int* trg;
879             int* src;
880             copyEmplaceImpl(trg, src);
881         }
882         {
883             const int* trg;
884             int* src;
885             copyEmplaceImpl(trg, src);
886         }
887         {
888             struct S{
889                 void* p;
890                 int i;
891             }
892             const S trg;
893             S src;
894             copyEmplaceImpl(trg, src);
895         }
896         {
897             struct S{
898                 void* p;
899                 int i;
900                 ~this(){}
901             }
902             const S trg;
903             S src;
904             copyEmplaceImpl(trg, src);
905         }
906         {
907             struct S{
908                 void* p;
909                 int i;
910                 ~this(){}
911             }
912             const S[4] trg;
913             S[4] src;
914             copyEmplaceImpl(trg, src);
915         }
916         {
917             static class B{}
918             static class D : B{}
919             {
920                 const B trg;
921                 D src;
922                 copyEmplaceImpl(trg, src);
923             }
924             {
925                 const B[] trg;
926                 D[] src;
927                 copyEmplaceImpl(trg, src);
928             }
929             {
930                 const B* trg;
931                 D* src;
932                 copyEmplaceImpl(trg, src);
933             }
934             {
935                 const B[4] trg;
936                 D[4] src;
937                 copyEmplaceImpl(trg, src);
938             }
939         }
940 
941         {
942             void delegate()@system trg;
943             void delegate()@safe src;
944             copyEmplaceImpl(trg, src);
945 
946         }
947 
948     }
949 }
950 
951 
952 
953