Home | History | Annotate | Line # | Download | only in internal
      1 /**
      2  This module contains the implementation of move semantics of DIP 1014
      3 
      4   Copyright: Copyright Digital Mars 2000 - 2019.
      5   License: Distributed under the
      6        $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
      7      (See accompanying file LICENSE)
      8   Source: $(DRUNTIMESRC core/_internal/_moving.d)
      9 */
     10 module core.internal.moving;
     11 
     12 /**
     13 Recursively calls the `opPostMove` callbacks of a struct and its members if
     14 they're defined.
     15 
     16 When moving a struct instance, the compiler emits a call to this function
     17 after blitting the instance and before releasing the original instance's
     18 memory.
     19 
     20 Params:
     21      newLocation = reference to struct instance being moved into
     22      oldLocation = reference to the original instance
     23 
     24 Note:
     25      This function is tentatively defined as `nothrow` to prevent
     26      `opPostMove` from being defined without `nothrow`, which would allow
     27      for possibly confusing changes in program flow.
     28 */
     29 void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow
     30     if (is(S == struct))
     31 {
     32     import core.internal.traits : hasElaborateMove;
     33     static foreach (i, M; typeof(S.tupleof))
     34     {
     35         static if (hasElaborateMove!M)
     36         {
     37             __move_post_blt(newLocation.tupleof[i], oldLocation.tupleof[i]);
     38         }
     39     }
     40 
     41     static if (__traits(hasMember, S, "opPostMove"))
     42     {
     43         import core.internal.traits : lvalueOf, rvalueOf;
     44         static assert( is(typeof(S.init.opPostMove(lvalueOf!S))) &&
     45                       !is(typeof(S.init.opPostMove(rvalueOf!S))),
     46                 "`" ~ S.stringof ~ ".opPostMove` must take exactly one argument of type `" ~ S.stringof ~ "` by reference");
     47 
     48         newLocation.opPostMove(oldLocation);
     49     }
     50 }
     51 
     52 void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow
     53     if (__traits(isStaticArray, S))
     54 {
     55     import core.internal.traits : hasElaborateMove;
     56     static if (S.length && hasElaborateMove!(typeof(newLocation[0])))
     57     {
     58         foreach (i; 0 .. S.length)
     59             __move_post_blt(newLocation[i], oldLocation[i]);
     60     }
     61 }
     62 
     63 @safe nothrow unittest
     64 {
     65     struct A
     66     {
     67         bool movedInto;
     68         void opPostMove(const ref A oldLocation)
     69         {
     70             movedInto = true;
     71         }
     72     }
     73     A src, dest;
     74     __move_post_blt(dest, src);
     75     assert(dest.movedInto);
     76 }
     77 
     78 @safe nothrow unittest
     79 {
     80     struct A
     81     {
     82         bool movedInto;
     83         void opPostMove(const ref A oldLocation)
     84         {
     85             movedInto = true;
     86         }
     87     }
     88     struct B
     89     {
     90         A a;
     91 
     92         bool movedInto;
     93         void opPostMove(const ref B oldLocation)
     94         {
     95             movedInto = true;
     96         }
     97     }
     98     B src, dest;
     99     __move_post_blt(dest, src);
    100     assert(dest.movedInto && dest.a.movedInto);
    101 }
    102 
    103 @safe nothrow unittest
    104 {
    105     static struct DoNotMove
    106     {
    107         bool movedInto;
    108         void opPostMove(const ref DoNotMove oldLocation)
    109         {
    110             movedInto = true;
    111         }
    112     }
    113     static DoNotMove doNotMove;
    114 
    115     struct A
    116     {
    117         @property ref DoNotMove member()
    118         {
    119             return doNotMove;
    120         }
    121     }
    122     A src, dest;
    123     __move_post_blt(dest, src);
    124     assert(!doNotMove.movedInto);
    125 }
    126 
    127 @safe nothrow unittest
    128 {
    129     static struct A
    130     {
    131         bool movedInto;
    132         void opPostMove(const ref A oldLocation)
    133         {
    134             movedInto = true;
    135         }
    136     }
    137     static struct B
    138     {
    139         A[2] a;
    140     }
    141     B src, dest;
    142     __move_post_blt(dest, src);
    143     foreach (ref a; src.a)
    144         assert(!a.movedInto);
    145     foreach (ref a; dest.a)
    146         assert(a.movedInto);
    147 }
    148