diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-08-25 19:04:50 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-08-28 00:16:34 +0200 |
commit | b7a586beae1027ea0c82411637920a5032d1dedf (patch) | |
tree | 4c41a84c4113e90cd0caaa7aa9925f4232dc22d5 /libphobos/libdruntime | |
parent | cace77f4fb8df18c01dfdf9040cc944eedef1147 (diff) | |
download | gcc-b7a586beae1027ea0c82411637920a5032d1dedf.zip gcc-b7a586beae1027ea0c82411637920a5032d1dedf.tar.gz gcc-b7a586beae1027ea0c82411637920a5032d1dedf.tar.bz2 |
d: Merge upstream dmd 817610b16d, phobos b578dfad9
D front-end changes:
- Import latest bug fixes to mainline.
Phobos changes:
- Import latest bug fixes to mainline.
- std.logger module has been moved out of experimental.
- Removed std.experimental.typecons module.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 817610b16d.
* d-ctfloat.cc (CTFloat::parse): Update for new front-end interface.
* d-lang.cc (d_parse_file): Likewise.
* expr.cc (ExprVisitor::visit (AssignExp *)): Remove handling of array
assignments to non-trivial static and dynamic arrays.
* runtime.def (ARRAYASSIGN): Remove.
(ARRAYASSIGN_L): Remove.
(ARRAYASSIGN_R): Remove.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 817610b16d.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
core/internal/array/arrayassign.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos b578dfad9.
* src/Makefile.am (PHOBOS_DSOURCES): Remove
std/experimental/typecons.d. Add std/logger package.
* src/Makefile.in: Regenerate.
Diffstat (limited to 'libphobos/libdruntime')
-rw-r--r-- | libphobos/libdruntime/MERGE | 2 | ||||
-rw-r--r-- | libphobos/libdruntime/Makefile.am | 23 | ||||
-rw-r--r-- | libphobos/libdruntime/Makefile.in | 26 | ||||
-rw-r--r-- | libphobos/libdruntime/core/demangle.d | 2 | ||||
-rw-r--r-- | libphobos/libdruntime/core/exception.d | 10 | ||||
-rw-r--r-- | libphobos/libdruntime/core/internal/array/arrayassign.d | 304 | ||||
-rw-r--r-- | libphobos/libdruntime/core/internal/array/equality.d | 27 | ||||
-rw-r--r-- | libphobos/libdruntime/core/sys/posix/sys/socket.d | 36 | ||||
-rw-r--r-- | libphobos/libdruntime/object.d | 91 | ||||
-rw-r--r-- | libphobos/libdruntime/rt/arrayassign.d | 165 |
10 files changed, 464 insertions, 222 deletions
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index c358b69..85fc49d 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -d7772a236983ec37b92d21b28bad3cd2de57b945 +817610b16d0f0f469b9fbb28c000956fb910c43f The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am index 2e1e91d..d828749 100644 --- a/libphobos/libdruntime/Makefile.am +++ b/libphobos/libdruntime/Makefile.am @@ -171,17 +171,18 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \ core/exception.d core/gc/config.d core/gc/gcinterface.d \ core/gc/registry.d core/int128.d core/internal/abort.d \ - core/internal/array/appending.d core/internal/array/capacity.d \ - core/internal/array/casting.d core/internal/array/comparison.d \ - core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/duplication.d core/internal/array/equality.d \ - core/internal/array/operations.d core/internal/array/utils.d \ - core/internal/atomic.d core/internal/attributes.d \ - core/internal/container/array.d core/internal/container/common.d \ - core/internal/container/hashtab.d core/internal/container/treap.d \ - core/internal/convert.d core/internal/dassert.d \ - core/internal/destruction.d core/internal/entrypoint.d \ - core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ + core/internal/array/appending.d core/internal/array/arrayassign.d \ + core/internal/array/capacity.d core/internal/array/casting.d \ + core/internal/array/comparison.d core/internal/array/concatenation.d \ + core/internal/array/construction.d core/internal/array/duplication.d \ + core/internal/array/equality.d core/internal/array/operations.d \ + core/internal/array/utils.d core/internal/atomic.d \ + core/internal/attributes.d core/internal/container/array.d \ + core/internal/container/common.d core/internal/container/hashtab.d \ + core/internal/container/treap.d core/internal/convert.d \ + core/internal/dassert.d core/internal/destruction.d \ + core/internal/entrypoint.d core/internal/gc/bits.d \ + core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in index de6656c..57660ee 100644 --- a/libphobos/libdruntime/Makefile.in +++ b/libphobos/libdruntime/Makefile.in @@ -192,6 +192,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \ core/demangle.lo core/exception.lo core/gc/config.lo \ core/gc/gcinterface.lo core/gc/registry.lo core/int128.lo \ core/internal/abort.lo core/internal/array/appending.lo \ + core/internal/array/arrayassign.lo \ core/internal/array/capacity.lo core/internal/array/casting.lo \ core/internal/array/comparison.lo \ core/internal/array/concatenation.lo \ @@ -839,17 +840,18 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \ core/builtins.d core/checkedint.d core/cpuid.d core/demangle.d \ core/exception.d core/gc/config.d core/gc/gcinterface.d \ core/gc/registry.d core/int128.d core/internal/abort.d \ - core/internal/array/appending.d core/internal/array/capacity.d \ - core/internal/array/casting.d core/internal/array/comparison.d \ - core/internal/array/concatenation.d core/internal/array/construction.d \ - core/internal/array/duplication.d core/internal/array/equality.d \ - core/internal/array/operations.d core/internal/array/utils.d \ - core/internal/atomic.d core/internal/attributes.d \ - core/internal/container/array.d core/internal/container/common.d \ - core/internal/container/hashtab.d core/internal/container/treap.d \ - core/internal/convert.d core/internal/dassert.d \ - core/internal/destruction.d core/internal/entrypoint.d \ - core/internal/gc/bits.d core/internal/gc/impl/conservative/gc.d \ + core/internal/array/appending.d core/internal/array/arrayassign.d \ + core/internal/array/capacity.d core/internal/array/casting.d \ + core/internal/array/comparison.d core/internal/array/concatenation.d \ + core/internal/array/construction.d core/internal/array/duplication.d \ + core/internal/array/equality.d core/internal/array/operations.d \ + core/internal/array/utils.d core/internal/atomic.d \ + core/internal/attributes.d core/internal/container/array.d \ + core/internal/container/common.d core/internal/container/hashtab.d \ + core/internal/container/treap.d core/internal/convert.d \ + core/internal/dassert.d core/internal/destruction.d \ + core/internal/entrypoint.d core/internal/gc/bits.d \ + core/internal/gc/impl/conservative/gc.d \ core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \ core/internal/gc/os.d core/internal/gc/pooltable.d \ core/internal/gc/proxy.d core/internal/hash.d core/internal/lifetime.d \ @@ -1201,6 +1203,8 @@ core/internal/array/$(am__dirstamp): @$(MKDIR_P) core/internal/array @: > core/internal/array/$(am__dirstamp) core/internal/array/appending.lo: core/internal/array/$(am__dirstamp) +core/internal/array/arrayassign.lo: \ + core/internal/array/$(am__dirstamp) core/internal/array/capacity.lo: core/internal/array/$(am__dirstamp) core/internal/array/casting.lo: core/internal/array/$(am__dirstamp) core/internal/array/comparison.lo: \ diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d index cb8d433..ca87f90 100644 --- a/libphobos/libdruntime/core/demangle.d +++ b/libphobos/libdruntime/core/demangle.d @@ -2328,7 +2328,7 @@ char[] mangle(T)(return scope const(char)[] fqn, return scope char[] dst = null) @property bool empty() const { return !s.length; } - @property const(char)[] front() const return + @property const(char)[] front() const return scope { immutable i = indexOfDot(); return i == -1 ? s[0 .. $] : s[0 .. i]; diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d index 81aa43b..a05a24c 100644 --- a/libphobos/libdruntime/core/exception.d +++ b/libphobos/libdruntime/core/exception.d @@ -14,7 +14,7 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted { // Consider making this a compile time check. version (D_Exceptions) - throw staticError!SwitchError(file, line, null); + throw staticError!SwitchError("No appropriate switch clause found", file, line, null); else assert(0, "No appropriate switch clause found"); } @@ -446,16 +446,16 @@ class ForkError : Error */ class SwitchError : Error { - @safe pure nothrow @nogc this( string file = __FILE__, size_t line = __LINE__, Throwable next = null ) + @safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null ) { - super( "No appropriate switch clause found", file, line, next ); + super( msg, file, line, next ); } } unittest { { - auto se = new SwitchError(); + auto se = new SwitchError("No appropriate switch clause found"); assert(se.file == __FILE__); assert(se.line == __LINE__ - 2); assert(se.next is null); @@ -463,7 +463,7 @@ unittest } { - auto se = new SwitchError("hello", 42, new Exception("It's an Exception!")); + auto se = new SwitchError("No appropriate switch clause found", "hello", 42, new Exception("It's an Exception!")); assert(se.file == "hello"); assert(se.line == 42); assert(se.next !is null); diff --git a/libphobos/libdruntime/core/internal/array/arrayassign.d b/libphobos/libdruntime/core/internal/array/arrayassign.d new file mode 100644 index 0000000..6132e68 --- /dev/null +++ b/libphobos/libdruntime/core/internal/array/arrayassign.d @@ -0,0 +1,304 @@ +module core.internal.array.arrayassign; + +// Force `enforceRawArraysConformable` to remain `pure` `@nogc` +private void enforceRawArraysConformable(const char[] action, const size_t elementSize, + const void[] a1, const void[] a2, const bool allowOverlap) @trusted @nogc pure nothrow +{ + import core.internal.util.array : enforceRawArraysConformable; + + alias Type = void function(const char[] action, const size_t elementSize, + const void[] a1, const void[] a2, in bool allowOverlap = false) @nogc pure nothrow; + (cast(Type)&enforceRawArraysConformable)(action, elementSize, a1, a2, allowOverlap); +} + +private template CopyElem(string CopyAction) +{ + const char[] CopyElem = "{\n" ~ q{ + memcpy(&tmp, cast(void*) &dst, elemSize); + } ~ CopyAction ~ q{ + auto elem = cast(Unqual!T*) &tmp; + destroy(*elem); + } ~ "}\n"; +} + +private template CopyArray(bool CanOverlap, string CopyAction) +{ + const char[] CopyArray = CanOverlap ? q{ + if (vFrom.ptr < vTo.ptr && vTo.ptr < vFrom.ptr + elemSize * vFrom.length) + foreach_reverse (i, ref dst; to) + } ~ CopyElem!(CopyAction) ~ q{ + else + foreach (i, ref dst; to) + } ~ CopyElem!(CopyAction) + : q{ + foreach (i, ref dst; to) + } ~ CopyElem!(CopyAction); +} + +private template ArrayAssign(string CopyLogic, string AllowOverLap) +{ + const char[] ArrayAssign = q{ + import core.internal.traits : hasElaborateCopyConstructor, Unqual; + import core.lifetime : copyEmplace; + import core.stdc.string : memcpy; + + void[] vFrom = (cast(void*) from.ptr)[0 .. from.length]; + void[] vTo = (cast(void*) to.ptr)[0 .. to.length]; + enum elemSize = T.sizeof; + + enforceRawArraysConformable("copy", elemSize, vFrom, vTo, } ~ AllowOverLap ~ q{); + + void[elemSize] tmp = void; + + } ~ CopyLogic ~ q{ + + return to; + }; +} + +/** + * Does array assignment (not construction) from another array of the same + * element type. Handles overlapping copies. Assumes the right hand side is an + * lvalue, + * + * Used for static array assignment with non-POD element types: + * --- + * struct S + * { + * ~this() {} // destructor, so not Plain Old Data + * } + * + * void main() + * { + * S[3] arr; + * S[3] lvalue; + * + * arr = lvalue; + * // Generates: + * // _d_arrayassign_l(arr[], lvalue[]), arr; + * } + * --- + * + * Params: + * to = destination array + * from = source array + * Returns: + * `to` + */ +Tarr _d_arrayassign_l(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted +{ + mixin(ArrayAssign!(q{ + static if (hasElaborateCopyConstructor!T) + } ~ CopyArray!(true, "copyEmplace(from[i], dst);") ~ q{ + else + } ~ CopyArray!(true, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"), + "true")); +} + +@safe unittest +{ + int counter; + struct S + { + int val; + this(int val) { this.val = val; } + this(const scope ref S rhs) + { + val = rhs.val; + counter++; + } + } + + S[4] arr1; + S[4] arr2 = [S(0), S(1), S(2), S(3)]; + _d_arrayassign_l(arr1[], arr2[]); + + assert(counter == 4); + assert(arr1 == arr2); +} + +// copy constructor +@safe unittest +{ + int counter; + struct S + { + int val; + this(int val) { this.val = val; } + this(const scope ref S rhs) + { + val = rhs.val; + counter++; + } + } + + S[4] arr1; + S[4] arr2 = [S(0), S(1), S(2), S(3)]; + _d_arrayassign_l(arr1[], arr2[]); + + assert(counter == 4); + assert(arr1 == arr2); +} + +@safe nothrow unittest +{ + // Test that throwing works + int counter; + bool didThrow; + + struct Throw + { + int val; + this(this) + { + counter++; + if (counter == 2) + throw new Exception(""); + } + } + try + { + Throw[4] a; + Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)]; + _d_arrayassign_l(a[], b[]); + } + catch (Exception) + { + didThrow = true; + } + assert(didThrow); + assert(counter == 2); + + + // Test that `nothrow` works + didThrow = false; + counter = 0; + struct NoThrow + { + int val; + this(this) + { + counter++; + } + } + try + { + NoThrow[4] a; + NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)]; + _d_arrayassign_l(a[], b[]); + } + catch (Exception) + { + didThrow = false; + } + assert(!didThrow); + assert(counter == 4); +} + +/** + * Does array assignment (not construction) from another array of the same + * element type. Does not support overlapping copies. Assumes the right hand + * side is an rvalue, + * + * Used for static array assignment with non-POD element types: + * --- + * struct S + * { + * ~this() {} // destructor, so not Plain Old Data + * } + * + * void main() + * { + * S[3] arr; + * S[3] getRvalue() {return lvalue;} + * + * arr = getRvalue(); + * // Generates: + * // (__appendtmp = getRvalue), _d_arrayassign_l(arr[], __appendtmp), arr; + * } + * --- + * + * Params: + * to = destination array + * from = source array + * Returns: + * `to` + */ +Tarr _d_arrayassign_r(Tarr : T[], T)(return scope Tarr to, scope Tarr from) @trusted +{ + mixin(ArrayAssign!( + CopyArray!(false, "memcpy(cast(void*) &dst, cast(void*) &from[i], elemSize);"), + "false")); +} + +@safe unittest +{ + int counter; + struct S + { + int val; + this(int val) { this.val = val; } + this(const scope ref S rhs) + { + val = rhs.val; + counter++; + } + } + + S[4] arr1; + S[4] arr2 = [S(0), S(1), S(2), S(3)]; + _d_arrayassign_r(arr1[], arr2[]); + + assert(counter == 0); + assert(arr1 == arr2); +} + +// copy constructor +@safe unittest +{ + int counter; + struct S + { + int val; + this(int val) { this.val = val; } + this(const scope ref S rhs) + { + val = rhs.val; + counter++; + } + } + + S[4] arr1; + S[4] arr2 = [S(0), S(1), S(2), S(3)]; + _d_arrayassign_r(arr1[], arr2[]); + + assert(counter == 0); + assert(arr1 == arr2); +} + +@safe nothrow unittest +{ + // Test that `nothrow` works + bool didThrow = false; + int counter = 0; + struct NoThrow + { + int val; + this(this) + { + counter++; + } + } + try + { + NoThrow[4] a; + NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)]; + _d_arrayassign_r(a[], b[]); + } + catch (Exception) + { + didThrow = false; + } + assert(!didThrow); + assert(counter == 0); +} diff --git a/libphobos/libdruntime/core/internal/array/equality.d b/libphobos/libdruntime/core/internal/array/equality.d index d3fdd65..c110d64 100644 --- a/libphobos/libdruntime/core/internal/array/equality.d +++ b/libphobos/libdruntime/core/internal/array/equality.d @@ -236,6 +236,33 @@ unittest static assert(!useMemcmp!(int[], int[])); } +// https://issues.dlang.org/show_bug.cgi?id=21094 +unittest +{ + static class C + { + int a; + } + static struct S + { + bool isValid; + C fib; + + inout(C) get() pure @safe @nogc nothrow inout + { + return isValid ? fib : C.init; + } + T opCast(T : C)() const { return null; } + + alias get this; + } + + auto foo(S[] lhs, S[] rhs) + { + return lhs == rhs; + } +} + // Returns a reference to an array element, eliding bounds check and // casting void to ubyte. pragma(inline, true) diff --git a/libphobos/libdruntime/core/sys/posix/sys/socket.d b/libphobos/libdruntime/core/sys/posix/sys/socket.d index 3a7b753..fc5dc5d 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/socket.d +++ b/libphobos/libdruntime/core/sys/posix/sys/socket.d @@ -188,10 +188,40 @@ version (linux) extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); } - private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc; - extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc + version (CRuntime_Musl) { - return __cmsg_nxthdr(msg, cmsg); + extern (D) + { + private size_t __CMSG_LEN(inout(cmsghdr)* cmsg) pure nothrow @nogc + { + return (cmsg.cmsg_len + size_t.sizeof -1) & cast(size_t)(~(size_t.sizeof - 1)); + } + + private inout(cmsghdr)* __CMSG_NEXT(inout(cmsghdr)* cmsg) pure nothrow @nogc + { + return cmsg + __CMSG_LEN(cmsg); + } + + private inout(msghdr)* __MHDR_END(inout(msghdr)* mhdr) pure nothrow @nogc + { + return cast(inout(msghdr)*)(mhdr.msg_control + mhdr.msg_controllen); + } + + inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc + { + return cmsg.cmsg_len < cmsghdr.sizeof || + __CMSG_LEN(cmsg) + cmsghdr.sizeof >= __MHDR_END(msg) - cast(inout(msghdr)*)(cmsg) + ? cast(inout(cmsghdr)*) null : cast(inout(cmsghdr)*) __CMSG_NEXT(cmsg); + } + } + } + else + { + private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc; + extern (D) inout(cmsghdr)* CMSG_NXTHDR(inout(msghdr)* msg, inout(cmsghdr)* cmsg) pure nothrow @nogc + { + return __cmsg_nxthdr(msg, cmsg); + } } extern (D) inout(cmsghdr)* CMSG_FIRSTHDR( inout(msghdr)* mhdr ) pure nothrow @nogc diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index 8ef65489..d842499 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -6,6 +6,7 @@ * $(TR $(TD Arrays) $(TD * $(MYREF assumeSafeAppend) * $(MYREF capacity) + * $(A #.dup.2, $(TT dup)) * $(MYREF idup) * $(MYREF reserve) * )) @@ -14,6 +15,7 @@ * $(MYREF byKeyValue) * $(MYREF byValue) * $(MYREF clear) + * $(MYREF dup) * $(MYREF get) * $(MYREF keys) * $(MYREF rehash) @@ -23,15 +25,15 @@ * )) * $(TR $(TD General) $(TD * $(MYREF destroy) - * $(MYREF dup) * $(MYREF hashOf) - * $(MYREF opEquals) + * $(MYREF imported) + * $(MYREF noreturn) * )) - * $(TR $(TD Types) $(TD + * $(TR $(TD Classes) $(TD * $(MYREF Error) * $(MYREF Exception) - * $(MYREF noreturn) * $(MYREF Object) + * $(MYREF opEquals) * $(MYREF Throwable) * )) * $(TR $(TD Type info) $(TD @@ -61,7 +63,11 @@ alias size_t = typeof(int.sizeof); alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0); alias sizediff_t = ptrdiff_t; // For backwards compatibility only. -alias noreturn = typeof(*null); /// bottom type +/** + * Bottom type. + * See $(DDSUBLINK spec/type, noreturn). + */ +alias noreturn = typeof(*null); alias hash_t = size_t; // For backwards compatibility only. alias equals_t = bool; // For backwards compatibility only. @@ -266,7 +272,9 @@ class Object the typeinfo name string compare. This is because of dmd's dll implementation. However, it can infer to @safe if your class' opEquals is. +/ -bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) if (is(LHS : const Object) && is(RHS : const Object)) +bool opEquals(LHS, RHS)(LHS lhs, RHS rhs) +if ((is(LHS : const Object) || is(LHS : const shared Object)) && + (is(RHS : const Object) || is(RHS : const shared Object))) { static if (__traits(compiles, lhs.opEquals(rhs)) && __traits(compiles, rhs.opEquals(lhs))) { @@ -505,6 +513,16 @@ unittest assert(obj1 != obj2); } +// https://issues.dlang.org/show_bug.cgi?id=23291 +@system unittest +{ + static shared class C { bool opEquals(const(shared(C)) rhs) const shared { return true;}} + const(C) c = new C(); + const(C)[] a = [c]; + const(C)[] b = [c]; + assert(a[0] == b[0]); +} + private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow; void setSameMutex(shared Object ownee, shared Object owner) @@ -3473,13 +3491,18 @@ ref V require(K, V)(ref V[K] aa, K key, lazy V value = V.init) private enum bool isSafeCopyable(T) = is(typeof(() @safe { union U { T x; } T *x; auto u = U(*x); })); /*********************************** - * Looks up key; if it exists applies the update callable else evaluates the - * create callable and adds it to the associative array + * Calls `create` if `key` doesn't exist in the associative array, + * otherwise calls `update`. + * `create` returns a corresponding value for `key`. + * `update` accepts a key parameter. If it returns a value, the value is + * set for `key`. * Params: * aa = The associative array. * key = The key. - * create = The callable to apply on create. - * update = The callable to apply on update. + * create = The callable to create a value for `key`. + * Must return V. + * update = The callable to call if `key` exists. + * Takes a K argument, returns a V or void. */ void update(K, V, C, U)(ref V[K] aa, K key, scope C create, scope U update) if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof(update(aa[K.init])) == void))) @@ -3509,23 +3532,39 @@ if (is(typeof(create()) : V) && (is(typeof(update(aa[K.init])) : V) || is(typeof } /// -@system unittest +@safe unittest { - auto aa = ["k1": 1]; + int[string] aa; - aa.update("k1", { - return -1; // create (won't be executed) - }, (ref int v) { - v += 1; // update - }); - assert(aa["k1"] == 2); - - aa.update("k2", { - return 0; // create - }, (ref int v) { - v = -1; // update (won't be executed) - }); - assert(aa["k2"] == 0); + // create + aa.update("key", + () => 1, + (int) {} // not executed + ); + assert(aa["key"] == 1); + + // update value by ref + aa.update("key", + () => 0, // not executed + (ref int v) { + v += 1; + }); + assert(aa["key"] == 2); + + // update from return value + aa.update("key", + () => 0, // not executed + (int v) => v * 2 + ); + assert(aa["key"] == 4); + + // 'update' without changing value + aa.update("key", + () => 0, // not executed + (int) { + // do something else + }); + assert(aa["key"] == 4); } @safe unittest @@ -4576,6 +4615,8 @@ public import core.internal.array.casting: __ArrayCast; public import core.internal.array.concatenation : _d_arraycatnTXImpl; public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; +public import core.internal.array.arrayassign : _d_arrayassign_l; +public import core.internal.array.arrayassign : _d_arrayassign_r; public import core.internal.array.capacity: _d_arraysetlengthTImpl; public import core.internal.dassert: _d_assert_fail; diff --git a/libphobos/libdruntime/rt/arrayassign.d b/libphobos/libdruntime/rt/arrayassign.d index c9db2fc..c9e2b15 100644 --- a/libphobos/libdruntime/rt/arrayassign.d +++ b/libphobos/libdruntime/rt/arrayassign.d @@ -19,171 +19,6 @@ private debug(PRINTF) import core.stdc.stdio; } -/* - * Superseded array assignment hook. Does not take into account destructors: - * https://issues.dlang.org/show_bug.cgi?id=13661 - * Kept for backward binary compatibility. This function can be removed in the future. - */ -extern (C) void[] _d_arrayassign(TypeInfo ti, void[] from, void[] to) -{ - debug(PRINTF) printf("_d_arrayassign(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize); - - immutable elementSize = ti.tsize; - - // Need a temporary buffer tmp[] big enough to hold one element - void[16] buf = void; - void* ptmp = (elementSize > buf.sizeof) ? malloc(elementSize) : buf.ptr; - scope (exit) - { - if (ptmp != buf.ptr) - free(ptmp); - } - return _d_arrayassign_l(ti, from, to, ptmp); -} - -/** -Does array assignment (not construction) from another array of the same -element type. - -Handles overlapping copies. - -The `_d_arrayassign_l` variant assumes the right hand side is an lvalue, -while `_d_arrayassign_r` assumes it's an rvalue, which means it doesn't have to call copy constructors. - -Used for static array assignment with non-POD element types: ---- -struct S -{ - ~this() {} // destructor, so not Plain Old Data -} - -void main() -{ - S[3] arr; - S[3] lvalue; - - arr = lvalue; - // Generates: - // S _tmp; - // _d_arrayassign_l(typeid(S), (cast(void*) lvalue.ptr)[0..lvalue.length], (cast(void*) arr.ptr)[0..arr.length], &_tmp); - - S[3] getRvalue() {return lvalue;} - arr = getRvalue(); - // Similar, but `_d_arrayassign_r` -} ---- - -Params: - ti = `TypeInfo` of the array element type. - dst = target memory. Its `.length` is equal to the element count, not byte length. - src = source memory. Its `.length` is equal to the element count, not byte length. - ptmp = Temporary memory for element swapping, must have capacity of `ti.tsize` bytes. -Returns: `dst` -*/ -extern (C) void[] _d_arrayassign_l(TypeInfo ti, void[] src, void[] dst, void* ptmp) -{ - debug(PRINTF) printf("_d_arrayassign_l(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); - - immutable elementSize = ti.tsize; - - enforceRawArraysConformable("copy", elementSize, src, dst, true); - - if (src.ptr < dst.ptr && dst.ptr < src.ptr + elementSize * src.length) - { - // If dst is in the middle of src memory, use reverse order. - for (auto i = dst.length; i--; ) - { - void* pdst = dst.ptr + i * elementSize; - void* psrc = src.ptr + i * elementSize; - memcpy(ptmp, pdst, elementSize); - memcpy(pdst, psrc, elementSize); - ti.postblit(pdst); - ti.destroy(ptmp); - } - } - else - { - // Otherwise, use normal order. - foreach (i; 0 .. dst.length) - { - void* pdst = dst.ptr + i * elementSize; - void* psrc = src.ptr + i * elementSize; - memcpy(ptmp, pdst, elementSize); - memcpy(pdst, psrc, elementSize); - ti.postblit(pdst); - ti.destroy(ptmp); - } - } - return dst; -} - -unittest // Bugzilla 14024 -{ - string op; - - struct S - { - char x = 'x'; - this(this) { op ~= x-0x20; } // upper case - ~this() { op ~= x; } // lower case - } - - S[4] mem; - ref S[2] slice(int a, int b) { return mem[a .. b][0 .. 2]; } - - op = null; - mem[0].x = 'a'; - mem[1].x = 'b'; - mem[2].x = 'x'; - mem[3].x = 'y'; - slice(0, 2) = slice(2, 4); // [ab] = [xy] - assert(op == "XaYb", op); - - op = null; - mem[0].x = 'x'; - mem[1].x = 'y'; - mem[2].x = 'a'; - mem[3].x = 'b'; - slice(2, 4) = slice(0, 2); // [ab] = [xy] - assert(op == "XaYb", op); - - op = null; - mem[0].x = 'a'; - mem[1].x = 'b'; - mem[2].x = 'c'; - slice(0, 2) = slice(1, 3); // [ab] = [bc] - assert(op == "BaCb", op); - - op = null; - mem[0].x = 'x'; - mem[1].x = 'y'; - mem[2].x = 'z'; - slice(1, 3) = slice(0, 2); // [yz] = [xy] - assert(op == "YzXy", op); -} - -/// ditto -extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* ptmp) -{ - debug(PRINTF) printf("_d_arrayassign_r(src = %p,%d, dst = %p,%d) size = %d\n", src.ptr, src.length, dst.ptr, dst.length, ti.tsize); - - immutable elementSize = ti.tsize; - - enforceRawArraysConformable("copy", elementSize, src, dst, false); - - // Always use normal order, because we can assume that - // the rvalue src has no overlapping with dst. - foreach (i; 0 .. dst.length) - { - void* pdst = dst.ptr + i * elementSize; - void* psrc = src.ptr + i * elementSize; - memcpy(ptmp, pdst, elementSize); - memcpy(pdst, psrc, elementSize); - ti.destroy(ptmp); - } - return dst; -} - /** Set all elements of an array to a single value. |