1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
|
/**
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);
}
|