| /** |
| 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); |
| } |