Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.

Move emplaceRef to core/internal #2498

Merged
merged 1 commit into from
Mar 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mak/COPY
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
1 change: 1 addition & 0 deletions mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
3 changes: 3 additions & 0 deletions mak/WINDOWS
Original file line number Diff line number Diff line change
Expand Up @@ -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 $** $@

Expand Down
109 changes: 109 additions & 0 deletions src/core/internal/lifetime.d
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
118 changes: 12 additions & 106 deletions src/core/lifetime.d
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -116,6 +10,8 @@ as `chunk`).
*/
T* emplace(T)(T* chunk) @safe pure nothrow
{
import core.internal.lifetime : emplaceRef;

emplaceRef!T(*chunk);
return chunk;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1176,6 +1076,8 @@ version (unittest)

@system unittest //Constness
{
import core.internal.lifetime : emplaceRef;

int a = void;
emplaceRef!(const int)(a, 5);

Expand All @@ -1200,6 +1102,8 @@ version (unittest)

pure nothrow @safe @nogc unittest
{
import core.internal.lifetime : emplaceRef;

int i;
emplaceRef(i);
emplaceRef!int(i);
Expand All @@ -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 {}
Expand Down