/** This module contains the implementation of move semantics of DIP 1014 Copyright: Copyright Digital Mars 2000 - 2019. License: Distributed under the $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). (See accompanying file LICENSE) Source: $(DRUNTIMESRC core/_internal/_moving.d) */ module core.internal.moving; /** Recursively calls the `opPostMove` callbacks of a struct and its members if they're defined. When moving a struct instance, the compiler emits a call to this function after blitting the instance and before releasing the original instance's memory. Params: newLocation = reference to struct instance being moved into oldLocation = reference to the original instance Note: This function is tentatively defined as `nothrow` to prevent `opPostMove` from being defined without `nothrow`, which would allow for possibly confusing changes in program flow. */ void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow if (is(S == struct)) { import core.internal.traits : hasElaborateMove; static foreach (i, M; typeof(S.tupleof)) { static if (hasElaborateMove!M) { __move_post_blt(newLocation.tupleof[i], oldLocation.tupleof[i]); } } static if (__traits(hasMember, S, "opPostMove")) { import core.internal.traits : lvalueOf, rvalueOf; static assert( is(typeof(S.init.opPostMove(lvalueOf!S))) && !is(typeof(S.init.opPostMove(rvalueOf!S))), "`" ~ S.stringof ~ ".opPostMove` must take exactly one argument of type `" ~ S.stringof ~ "` by reference"); newLocation.opPostMove(oldLocation); } } void __move_post_blt(S)(ref S newLocation, ref S oldLocation) nothrow if (__traits(isStaticArray, S)) { import core.internal.traits : hasElaborateMove; static if (S.length && hasElaborateMove!(typeof(newLocation[0]))) { foreach (i; 0 .. S.length) __move_post_blt(newLocation[i], oldLocation[i]); } } @safe nothrow unittest { struct A { bool movedInto; void opPostMove(const ref A oldLocation) { movedInto = true; } } A src, dest; __move_post_blt(dest, src); assert(dest.movedInto); } @safe nothrow unittest { struct A { bool movedInto; void opPostMove(const ref A oldLocation) { movedInto = true; } } struct B { A a; bool movedInto; void opPostMove(const ref B oldLocation) { movedInto = true; } } B src, dest; __move_post_blt(dest, src); assert(dest.movedInto && dest.a.movedInto); } @safe nothrow unittest { static struct DoNotMove { bool movedInto; void opPostMove(const ref DoNotMove oldLocation) { movedInto = true; } } static DoNotMove doNotMove; struct A { @property ref DoNotMove member() { return doNotMove; } } A src, dest; __move_post_blt(dest, src); assert(!doNotMove.movedInto); } @safe nothrow unittest { static struct A { bool movedInto; void opPostMove(const ref A oldLocation) { movedInto = true; } } static struct B { A[2] a; } B src, dest; __move_post_blt(dest, src); foreach (ref a; src.a) assert(!a.movedInto); foreach (ref a; dest.a) assert(a.movedInto); }