Projet_SETI_RISC-V/riscv-gnu-toolchain/gcc/libphobos/libdruntime/core/internal/postblit.d
2023-03-06 14:48:14 +01:00

275 lines
6 KiB
D

/**
This module contains support for D's postblit feature
Copyright: Copyright Digital Mars 2000 - 2019.
License: Distributed under the
$(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
(See accompanying file LICENSE)
Source: $(DRUNTIMESRC core/_internal/_destruction.d)
*/
module core.internal.postblit;
// compiler frontend lowers struct array postblitting to this
void __ArrayPostblit(T)(T[] a)
{
foreach (ref T e; a)
e.__xpostblit();
}
package void postblitRecurse(S)(ref S s)
if (is(S == struct))
{
static if (__traits(hasMember, S, "__xpostblit") &&
// Bugzilla 14746: Check that it's the exact member of S.
__traits(isSame, S, __traits(parent, s.__xpostblit)))
s.__xpostblit();
}
package void postblitRecurse(E, size_t n)(ref E[n] arr)
{
import core.internal.destruction: destructRecurse;
import core.internal.traits : hasElaborateCopyConstructor;
static if (hasElaborateCopyConstructor!E)
{
size_t i;
scope(failure)
{
for (; i != 0; --i)
{
destructRecurse(arr[i - 1]); // What to do if this throws?
}
}
for (i = 0; i < arr.length; ++i)
postblitRecurse(arr[i]);
}
}
// Test destruction/postblit order
@safe nothrow pure unittest
{
string[] order;
struct InnerTop
{
~this() @safe nothrow pure
{
order ~= "destroy inner top";
}
this(this) @safe nothrow pure
{
order ~= "copy inner top";
}
}
struct InnerMiddle {}
version (none) // https://issues.dlang.org/show_bug.cgi?id=14242
struct InnerElement
{
static char counter = '1';
~this() @safe nothrow pure
{
order ~= "destroy inner element #" ~ counter++;
}
this(this) @safe nothrow pure
{
order ~= "copy inner element #" ~ counter++;
}
}
struct InnerBottom
{
~this() @safe nothrow pure
{
order ~= "destroy inner bottom";
}
this(this) @safe nothrow pure
{
order ~= "copy inner bottom";
}
}
struct S
{
char[] s;
InnerTop top;
InnerMiddle middle;
version (none) InnerElement[3] array; // https://issues.dlang.org/show_bug.cgi?id=14242
int a;
InnerBottom bottom;
~this() @safe nothrow pure { order ~= "destroy outer"; }
this(this) @safe nothrow pure { order ~= "copy outer"; }
}
string[] destructRecurseOrder;
{
import core.internal.destruction: destructRecurse;
S s;
destructRecurse(s);
destructRecurseOrder = order;
order = null;
}
assert(order.length);
assert(destructRecurseOrder == order);
order = null;
S s;
postblitRecurse(s);
assert(order.length);
auto postblitRecurseOrder = order;
order = null;
S s2 = s;
assert(order.length);
assert(postblitRecurseOrder == order);
}
@safe unittest
{
// Bugzilla 14746
static struct HasPostblit
{
this(this) { assert(0); }
}
static struct Owner
{
HasPostblit* ptr;
alias ptr this;
}
Owner o;
assert(o.ptr is null);
postblitRecurse(o); // must not reach in HasPostblit.__postblit()
}
// Test handling of fixed-length arrays
// Separate from first test because of https://issues.dlang.org/show_bug.cgi?id=14242
@safe unittest
{
string[] order;
struct S
{
char id;
this(this)
{
order ~= "copy #" ~ id;
}
~this()
{
order ~= "destroy #" ~ id;
}
}
string[] destructRecurseOrder;
{
import core.internal.destruction: destructRecurse;
S[3] arr = [S('1'), S('2'), S('3')];
destructRecurse(arr);
destructRecurseOrder = order;
order = null;
}
assert(order.length);
assert(destructRecurseOrder == order);
order = null;
S[3] arr = [S('1'), S('2'), S('3')];
postblitRecurse(arr);
assert(order.length);
auto postblitRecurseOrder = order;
order = null;
auto arrCopy = arr;
assert(order.length);
assert(postblitRecurseOrder == order);
}
// Test handling of failed postblit
// Not nothrow or @safe because of https://issues.dlang.org/show_bug.cgi?id=14242
/+ nothrow @safe +/ unittest
{
static class FailedPostblitException : Exception { this() nothrow @safe { super(null); } }
static string[] order;
static struct Inner
{
char id;
@safe:
this(this)
{
order ~= "copy inner #" ~ id;
if (id == '2')
throw new FailedPostblitException();
}
~this() nothrow
{
order ~= "destroy inner #" ~ id;
}
}
static struct Outer
{
Inner inner1, inner2, inner3;
nothrow @safe:
this(char first, char second, char third)
{
inner1 = Inner(first);
inner2 = Inner(second);
inner3 = Inner(third);
}
this(this)
{
order ~= "copy outer";
}
~this()
{
order ~= "destroy outer";
}
}
auto outer = Outer('1', '2', '3');
try postblitRecurse(outer);
catch (FailedPostblitException) {}
catch (Exception) assert(false);
auto postblitRecurseOrder = order;
order = null;
try auto copy = outer;
catch (FailedPostblitException) {}
catch (Exception) assert(false);
assert(postblitRecurseOrder == order);
order = null;
Outer[3] arr = [Outer('1', '1', '1'), Outer('1', '2', '3'), Outer('3', '3', '3')];
try postblitRecurse(arr);
catch (FailedPostblitException) {}
catch (Exception) assert(false);
postblitRecurseOrder = order;
order = null;
try auto arrCopy = arr;
catch (FailedPostblitException) {}
catch (Exception) assert(false);
assert(postblitRecurseOrder == order);
}