From 64a5d4ec3959e5db5e27e95e08b54e847970816d Mon Sep 17 00:00:00 2001 From: Eduard Staniloiu Date: Wed, 27 Feb 2019 14:30:09 +0200 Subject: [PATCH] Move emplaceRef to core/internal --- mak/COPY | 1 + mak/SRCS | 1 + mak/WINDOWS | 3 + src/core/internal/lifetime.d | 109 ++++++++++++++++++++++++++++++++ src/core/lifetime.d | 118 ++++------------------------------- 5 files changed, 126 insertions(+), 106 deletions(-) create mode 100644 src/core/internal/lifetime.d diff --git a/mak/COPY b/mak/COPY index 9e0e361cbc..7b02a2f0b0 100644 --- a/mak/COPY +++ b/mak/COPY @@ -27,6 +27,7 @@ COPY=\ $(IMPDIR)\core\internal\string.d \ $(IMPDIR)\core\internal\traits.d \ $(IMPDIR)\core\internal\utf.d \ + $(IMPDIR)\core\internal\lifetime.d \ \ $(IMPDIR)\core\stdc\assert_.d \ $(IMPDIR)\core\stdc\complex.d \ diff --git a/mak/SRCS b/mak/SRCS index 4fa5f11f16..b5ca9bcd39 100644 --- a/mak/SRCS +++ b/mak/SRCS @@ -27,6 +27,7 @@ SRCS=\ src\core\internal\string.d \ src\core\internal\traits.d \ src\core\internal\utf.d \ + src\core\internal\lifetime.d \ \ src\core\stdc\assert_.d \ src\core\stdc\complex.d \ diff --git a/mak/WINDOWS b/mak/WINDOWS index 65b8080f2a..e9271e0f15 100644 --- a/mak/WINDOWS +++ b/mak/WINDOWS @@ -126,6 +126,9 @@ $(IMPDIR)\core\internal\traits.d : src\core\internal\traits.d $(IMPDIR)\core\internal\utf.d : src\core\internal\utf.d copy $** $@ +$(IMPDIR)\core\internal\lifetime.d : src\core\internal\lifetime.d + copy $** $@ + $(IMPDIR)\core\stdc\assert_.d : src\core\stdc\assert_.d copy $** $@ diff --git a/src/core/internal/lifetime.d b/src/core/internal/lifetime.d new file mode 100644 index 0000000000..c4966126b6 --- /dev/null +++ b/src/core/internal/lifetime.d @@ -0,0 +1,109 @@ +module core.internal.lifetime; + +/+ +emplaceRef is a package function for druntime internal use. It works like +emplace, but takes its argument by ref (as opposed to "by pointer"). +This makes it easier to use, easier to be safe, and faster in a non-inline +build. +Furthermore, emplaceRef optionally takes a type parameter, which specifies +the type we want to build. This helps to build qualified objects on mutable +buffer, without breaking the type system with unsafe casts. ++/ +void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) +{ + static if (args.length == 0) + { + static assert(is(typeof({static T i;})), + "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ + ".this() is annotated with @disable."); + static if (is(T == class)) static assert(!__traits(isAbstractClass, T), + T.stringof ~ " is abstract and it can't be emplaced"); + emplaceInitializer(chunk); + } + else static if ( + !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ + || + Args.length == 1 && is(typeof({T t = args[0];})) /* conversions */ + || + is(typeof(T(args))) /* general constructors */) + { + static struct S + { + T payload; + this(ref Args x) + { + static if (Args.length == 1) + static if (is(typeof(payload = x[0]))) + payload = x[0]; + else + payload = T(x[0]); + else + payload = T(x); + } + } + if (__ctfe) + { + static if (is(typeof(chunk = T(args)))) + chunk = T(args); + else static if (args.length == 1 && is(typeof(chunk = args[0]))) + chunk = args[0]; + else assert(0, "CTFE emplace doesn't support " + ~ T.stringof ~ " from " ~ Args.stringof); + } + else + { + S* p = () @trusted { return cast(S*) &chunk; }(); + static if (UT.sizeof > 0) + emplaceInitializer(*p); + p.__ctor(args); + } + } + else static if (is(typeof(chunk.__ctor(args)))) + { + // This catches the rare case of local types that keep a frame pointer + emplaceInitializer(chunk); + chunk.__ctor(args); + } + else + { + //We can't emplace. Try to diagnose a disabled postblit. + static assert(!(Args.length == 1 && is(Args[0] : T)), + "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ + ".this(this) is annotated with @disable."); + + //We can't emplace. + static assert(false, + T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ "."); + } +} + +// ditto +static import core.internal.traits; +void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) +if (is(UT == core.internal.traits.Unqual!UT)) +{ + emplaceRef!(UT, UT)(chunk, args); +} + +//emplace helper functions +private nothrow pure @trusted +void emplaceInitializer(T)(scope ref T chunk) +{ + import core.internal.traits : hasElaborateAssign, isAssignable; + static if (!hasElaborateAssign!T && isAssignable!T) + chunk = T.init; + else + { + static if (__traits(isZeroInit, T)) + { + import core.stdc.string : memset; + memset(&chunk, 0, T.sizeof); + } + else + { + import core.stdc.string : memcpy; + static immutable T init = T.init; + memcpy(&chunk, &init, T.sizeof); + } + } +} diff --git a/src/core/lifetime.d b/src/core/lifetime.d index e494d8323b..93b562cd73 100644 --- a/src/core/lifetime.d +++ b/src/core/lifetime.d @@ -1,111 +1,5 @@ module core.lifetime; -/+ -emplaceRef is a package function for druntime internal use. It works like -emplace, but takes its argument by ref (as opposed to "by pointer"). -This makes it easier to use, easier to be safe, and faster in a non-inline -build. -Furthermore, emplaceRef optionally takes a type parameter, which specifies -the type we want to build. This helps to build qualified objects on mutable -buffer, without breaking the type system with unsafe casts. -+/ -private void emplaceRef(T, UT, Args...)(ref UT chunk, auto ref Args args) -{ - static if (args.length == 0) - { - static assert(is(typeof({static T i;})), - "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ - ".this() is annotated with @disable."); - static if (is(T == class)) static assert(!__traits(isAbstractClass, T), - T.stringof ~ " is abstract and it can't be emplaced"); - emplaceInitializer(chunk); - } - else static if ( - !is(T == struct) && Args.length == 1 /* primitives, enums, arrays */ - || - Args.length == 1 && is(typeof({T t = args[0];})) /* conversions */ - || - is(typeof(T(args))) /* general constructors */) - { - static struct S - { - T payload; - this(ref Args x) - { - static if (Args.length == 1) - static if (is(typeof(payload = x[0]))) - payload = x[0]; - else - payload = T(x[0]); - else - payload = T(x); - } - } - if (__ctfe) - { - static if (is(typeof(chunk = T(args)))) - chunk = T(args); - else static if (args.length == 1 && is(typeof(chunk = args[0]))) - chunk = args[0]; - else assert(0, "CTFE emplace doesn't support " - ~ T.stringof ~ " from " ~ Args.stringof); - } - else - { - S* p = () @trusted { return cast(S*) &chunk; }(); - static if (UT.sizeof > 0) - emplaceInitializer(*p); - p.__ctor(args); - } - } - else static if (is(typeof(chunk.__ctor(args)))) - { - // This catches the rare case of local types that keep a frame pointer - emplaceInitializer(chunk); - chunk.__ctor(args); - } - else - { - //We can't emplace. Try to diagnose a disabled postblit. - static assert(!(Args.length == 1 && is(Args[0] : T)), - "Cannot emplace a " ~ T.stringof ~ " because " ~ T.stringof ~ - ".this(this) is annotated with @disable."); - - //We can't emplace. - static assert(false, - T.stringof ~ " cannot be emplaced from " ~ Args[].stringof ~ "."); - } -} -// ditto -static import core.internal.traits; -private void emplaceRef(UT, Args...)(ref UT chunk, auto ref Args args) - if (is(UT == core.internal.traits.Unqual!UT)) -{ - emplaceRef!(UT, UT)(chunk, args); -} - -//emplace helper functions -private void emplaceInitializer(T)(scope ref T chunk) @trusted pure nothrow -{ - import core.internal.traits : hasElaborateAssign, isAssignable; - static if (!hasElaborateAssign!T && isAssignable!T) - chunk = T.init; - else - { - static if (__traits(isZeroInit, T)) - { - import core.stdc.string : memset; - memset(&chunk, 0, T.sizeof); - } - else - { - import core.stdc.string : memcpy; - static immutable T init = T.init; - memcpy(&chunk, &init, T.sizeof); - } - } -} - // emplace /** Given a pointer `chunk` to uninitialized memory (but already typed @@ -116,6 +10,8 @@ as `chunk`). */ T* emplace(T)(T* chunk) @safe pure nothrow { + import core.internal.lifetime : emplaceRef; + emplaceRef!T(*chunk); return chunk; } @@ -160,6 +56,8 @@ as `chunk`). T* emplace(T, Args...)(T* chunk, auto ref Args args) if (is(T == struct) || Args.length == 1) { + import core.internal.lifetime : emplaceRef; + emplaceRef!T(*chunk, args); return chunk; } @@ -366,6 +264,8 @@ T* emplace(T, Args...)(void[] chunk, auto ref Args args) if (!is(T == class)) { import core.internal.traits : Unqual; + import core.internal.lifetime : emplaceRef; + testEmplaceChunk(chunk, T.sizeof, T.alignof); emplaceRef!(T, Unqual!T)(*cast(Unqual!T*) chunk.ptr, args); return cast(T*) chunk.ptr; @@ -1176,6 +1076,8 @@ version (unittest) @system unittest //Constness { + import core.internal.lifetime : emplaceRef; + int a = void; emplaceRef!(const int)(a, 5); @@ -1200,6 +1102,8 @@ version (unittest) pure nothrow @safe @nogc unittest { + import core.internal.lifetime : emplaceRef; + int i; emplaceRef(i); emplaceRef!int(i); @@ -1210,6 +1114,8 @@ pure nothrow @safe @nogc unittest // Test attribute propagation for UDTs pure nothrow @safe /* @nogc */ unittest { + import core.internal.lifetime : emplaceRef; + static struct Safe { this(this) pure nothrow @safe @nogc {}