dlib/wasm/runtime/core/lifetime.d

112 lines
3.1 KiB
D

module core.lifetime;
void copyEmplace(S, T)(ref S source, ref T target) @system
if (is(immutable S == immutable T))
{
import core.internal.traits : BaseElemOf, hasElaborateCopyConstructor, Unconst, Unqual;
// cannot have the following as simple template constraint due to nested-struct special case...
static if (!__traits(compiles, (ref S src) { T tgt = src; }))
{
alias B = BaseElemOf!T;
enum isNestedStruct = is(B == struct) && __traits(isNested, B);
static assert(isNestedStruct, "cannot copy-construct " ~ T.stringof ~ " from " ~ S.stringof);
}
void blit()
{
import core.stdc.string : memcpy;
memcpy(cast(Unqual!(T)*) &target, cast(Unqual!(T)*) &source, T.sizeof);
}
static if (is(T == struct))
{
static if (__traits(hasPostblit, T))
{
blit();
(cast() target).__xpostblit();
}
else static if (__traits(hasCopyConstructor, T))
{
// https://issues.dlang.org/show_bug.cgi?id=22766
import core.internal.lifetime : emplaceInitializer;
emplaceInitializer(*(cast(Unqual!T*)&target));
static if (__traits(isNested, T))
{
// copy context pointer
*(cast(void**) &target.tupleof[$-1]) = cast(void*) source.tupleof[$-1];
}
target.__ctor(source); // invoke copy ctor
}
else
{
blit(); // no opAssign
}
}
else static if (is(T == E[n], E, size_t n))
{
static if (hasElaborateCopyConstructor!E)
{
size_t i;
try
{
for (i = 0; i < n; i++)
copyEmplace(source[i], target[i]);
}
catch (Exception e)
{
// destroy, in reverse order, what we've constructed so far
while (i--)
destroy(*cast(Unconst!(E)*) &target[i]);
throw e;
}
}
else // trivial copy
{
blit(); // all elements at once
}
}
else
{
*cast(Unconst!(T)*) &target = *cast(Unconst!(T)*) &source;
}
}
T* emplace(T)(T* chunk) @safe pure nothrow
{
import core.internal.lifetime : emplaceRef;
emplaceRef!T(*chunk);
return chunk;
}
template forward(args...)
{
import core.internal.traits : AliasSeq;
template fwd(alias arg)
{
// by ref || lazy || const/immutable
static if (__traits(isRef, arg) ||
__traits(isOut, arg) ||
__traits(isLazy, arg) ||
!is(typeof(move(arg))))
alias fwd = arg;
// (r)value
else
@property auto fwd()
{
version (DigitalMars) { /* @@BUG 23890@@ */ } else pragma(inline, true);
return move(arg);
}
}
alias Result = AliasSeq!();
static foreach (arg; args)
Result = AliasSeq!(Result, fwd!arg);
static if (Result.length == 1)
alias forward = Result[0];
else
alias forward = Result;
}