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; opPostMoveA68 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; opPostMoveA83 void opPostMove(const ref A oldLocation) 84 { 85 movedInto = true; 86 } 87 } 88 struct B 89 { 90 A a; 91 92 bool movedInto; opPostMove(const ref B oldLocation)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; opPostMoveDoNotMove108 void opPostMove(const ref DoNotMove oldLocation) 109 { 110 movedInto = true; 111 } 112 } 113 static DoNotMove doNotMove; 114 115 struct A 116 { memberA117 @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; opPostMoveA132 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