diff --git a/source/tanya/conv.d b/source/tanya/conv.d index 57580ff..48cd11a 100644 --- a/source/tanya/conv.d +++ b/source/tanya/conv.d @@ -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. */