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
1 changed files with 38 additions and 22 deletions

View File

@ -14,6 +14,7 @@
*/
module tanya.conv;
import tanya.algorithm.mutation;
import tanya.container.string;
import tanya.format;
import tanya.memory;
@ -164,26 +165,12 @@ do
/// ditto
T* emplace(T, Args...)(void[] memory, auto ref Args args)
if (!isPolymorphicType!T && isAggregateType!T)
in
{
assert(memory.length >= T.sizeof);
}
out (result)
{
assert(memory.ptr is result);
}
do
in(memory.length >= T.sizeof)
out(result; memory.ptr is result)
{
auto result = (() @trusted => cast(T*) memory.ptr)();
static if (!hasElaborateAssign!T && isAssignable!T)
{
*result = T.init;
}
else
{
static const T init = T.init;
copy((cast(void*) &init)[0 .. T.sizeof], memory);
}
alias trustedCopy = (ref arg) @trusted =>
copy((cast(void*) &arg)[0 .. T.sizeof], memory);
static if (Args.length == 0)
{
@ -192,15 +179,25 @@ do
}
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);
}
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
{
@ -262,6 +259,25 @@ do
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.
*/