conv.emplace: Don't call a destructor

Don't call the destructor on uninitialized elements.
This commit is contained in:
Eugen Wissner 2018-10-13 11:30:02 +02:00
parent d0d682ca65
commit a04a04bb96

View File

@ -14,6 +14,7 @@
*/ */
module tanya.conv; module tanya.conv;
import tanya.algorithm.mutation;
import tanya.container.string; import tanya.container.string;
import tanya.format; import tanya.format;
import tanya.memory; import tanya.memory;
@ -164,26 +165,12 @@ do
/// ditto /// ditto
T* emplace(T, Args...)(void[] memory, auto ref Args args) T* emplace(T, Args...)(void[] memory, auto ref Args args)
if (!isPolymorphicType!T && isAggregateType!T) if (!isPolymorphicType!T && isAggregateType!T)
in in(memory.length >= T.sizeof)
{ out(result; memory.ptr is result)
assert(memory.length >= T.sizeof);
}
out (result)
{
assert(memory.ptr is result);
}
do
{ {
auto result = (() @trusted => cast(T*) memory.ptr)(); auto result = (() @trusted => cast(T*) memory.ptr)();
static if (!hasElaborateAssign!T && isAssignable!T) alias trustedCopy = (ref arg) @trusted =>
{ copy((cast(void*) &arg)[0 .. T.sizeof], memory);
*result = T.init;
}
else
{
static const T init = T.init;
copy((cast(void*) &init)[0 .. T.sizeof], memory);
}
static if (Args.length == 0) static if (Args.length == 0)
{ {
@ -192,15 +179,25 @@ do
} }
else static if (is(typeof(result.__ctor(args)))) else static if (is(typeof(result.__ctor(args))))
{ {
static if (!hasElaborateAssign!T && isAssignable!T)
{
*result = T.init;
}
else
{
static const T init = T.init;
trustedCopy(init);
}
result.__ctor(args); result.__ctor(args);
} }
else static if (is(typeof(T(args)))) else static if (Args.length == 1 && is(typeof({ T t = args[0]; })))
{ {
*result = T(args); trustedCopy(args[0]);
} }
else static if (is(typeof(*result = args))) // Args.length == 1, assignment else static if (is(typeof({ T t = T(args); })))
{ {
*result = args; auto init = T(args);
(() @trusted => moveEmplace(init, *result))();
} }
else else
{ {
@ -262,6 +259,25 @@ do
static assert(is(typeof(emplace!SWithDtor(null)))); static assert(is(typeof(emplace!SWithDtor(null))));
} }
// Doesn't call a destructor on uninitialized elements
@nogc nothrow pure @system unittest
{
static struct WithDtor
{
private bool canBeInvoked = false;
~this() @nogc nothrow pure @safe
{
if (!this.canBeInvoked)
{
assert(false);
}
}
}
void[WithDtor.sizeof] memory = void;
auto actual = emplace!WithDtor(memory[], WithDtor(true));
assert(actual.canBeInvoked);
}
/** /**
* Thrown if a type conversion fails. * Thrown if a type conversion fails.
*/ */