diff --git a/mak/COPY b/mak/COPY index 8265e2d6c9..f0f24e8c14 100644 --- a/mak/COPY +++ b/mak/COPY @@ -28,6 +28,7 @@ COPY=\ $(IMPDIR)\core\internal\dassert.d \ $(IMPDIR)\core\internal\entrypoint.d \ $(IMPDIR)\core\internal\hash.d \ + $(IMPDIR)\core\internal\moving.d \ $(IMPDIR)\core\internal\parseoptions.d \ $(IMPDIR)\core\internal\spinlock.d \ $(IMPDIR)\core\internal\string.d \ diff --git a/mak/DOCS b/mak/DOCS index 8f2fceefee..9cc7f5782d 100644 --- a/mak/DOCS +++ b/mak/DOCS @@ -76,6 +76,7 @@ DOCS=\ $(DOCDIR)\core_sys_darwin_netinet_in_.html \ \ $(DOCDIR)\core_internal_dassert.html \ + $(DOCDIR)\core_internal_moving.html \ $(DOCDIR)\core_internal_switch_.html \ \ $(DOCDIR)\core_internal_array_appending.html \ diff --git a/mak/SRCS b/mak/SRCS index a5e288df8a..fdc77af46c 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -27,6 +27,7 @@ SRCS=\ src\core\internal\dassert.d \ src\core\internal\entrypoint.d \ src\core\internal\hash.d \ + src\core\internal\moving.d \ src\core\internal\parseoptions.d \ src\core\internal\spinlock.d \ src\core\internal\string.d \ diff --git a/mak/WINDOWS b/mak/WINDOWS index 34439e7511..ce8ffb7328 100644 --- a/mak/WINDOWS +++ b/mak/WINDOWS @@ -138,6 +138,9 @@ $(IMPDIR)\core\internal\entrypoint.d : src\core\internal\entrypoint.d $(IMPDIR)\core\internal\hash.d : src\core\internal\hash.d copy $** $@ +$(IMPDIR)\core\internal\moving.d : src\core\internal\moving.d + copy $** $@ + $(IMPDIR)\core\internal\parseoptions.d : src\core\internal\parseoptions.d copy $** $@ diff --git a/posix.mak b/posix.mak index 150ece43bb..5790d3cc6e 100644 --- a/posix.mak +++ b/posix.mak @@ -177,6 +177,9 @@ $(DOCDIR)/core_sys_darwin_netinet_%.html : src/core/sys/darwin/netinet/%.d $(DMD $(DOCDIR)/core_internal_dassert.html : src/core/internal/dassert.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< +$(DOCDIR)/core_internal_moving.html : src/core/internal/moving.d $(DMD) + $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< + $(DOCDIR)/core_internal_switch_.html : src/core/internal/switch_.d $(DMD) $(DMD) $(DDOCFLAGS) -Df$@ project.ddoc $(DOCFMT) $< diff --git a/src/core/internal/moving.d b/src/core/internal/moving.d new file mode 100644 index 0000000000..15132876f3 --- /dev/null +++ b/src/core/internal/moving.d @@ -0,0 +1,89 @@ +/** + 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)) +{ + static foreach (memberName; __traits(allMembers, S)) + { + static if (is(typeof(__traits(getMember, S, memberName)) == struct)) + { + __move_post_blt(__traits(getMember, newLocation, memberName), __traits(getMember, oldLocation, memberName)); + } + } + + 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); + } +} + +@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); +} diff --git a/src/object.d b/src/object.d index 3c08b91967..e9f54b1cf1 100644 --- a/src/object.d +++ b/src/object.d @@ -45,85 +45,6 @@ public import core.internal.array.capacity: reserve; /// See $(REF assumeSafeAppend, core,internal,array,capacity) public import core.internal.array.capacity: assumeSafeAppend; -/** - * 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)) -{ - static foreach (memberName; __traits(allMembers, S)) - { - static if (is(typeof(__traits(getMember, S, memberName)) == struct)) - { - __move_post_blt(__traits(getMember, newLocation, memberName), __traits(getMember, oldLocation, memberName)); - } - } - - 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); - } -} - -@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); -} - /** Destroys the given object and optionally resets to initial state. It's used to _destroy an object, calling its destructor or finalizer so it no longer @@ -4101,6 +4022,9 @@ public import core.internal.array.capacity: _d_arraysetlengthTImpl; /// See $(REF _d_assert_fail, core,internal,dassert) public import core.internal.dassert: _d_assert_fail; +/// See $(REF __move_post_blt, core,internal,moving) +public import core.internal.moving: __move_post_blt; + /// See $(REF __switch, core,internal,switch_) public import core.internal.switch_: __switch; /// See $(REF __switch_error, core,internal,switch_)