Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1181 from JakobOvrum/destroy_preserve_attributes
Browse files Browse the repository at this point in the history
Make .destroy() work with attribute inference
  • Loading branch information
MartinNowak committed Apr 22, 2015
2 parents 7331dc3 + f98a021 commit 6d6aa3d
Show file tree
Hide file tree
Showing 3 changed files with 485 additions and 17 deletions.
97 changes: 97 additions & 0 deletions src/core/internal/traits.d
Expand Up @@ -95,3 +95,100 @@ template dtorIsNothrow(T)
{
enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
}

template anySatisfy(alias F, T...)
{
static if (T.length == 0)
{
enum anySatisfy = false;
}
else static if (T.length == 1)
{
enum anySatisfy = F!(T[0]);
}
else
{
enum anySatisfy =
anySatisfy!(F, T[ 0 .. $/2]) ||
anySatisfy!(F, T[$/2 .. $ ]);
}
}

// Somehow fails for non-static nested structs without support for aliases
template hasElaborateDestructor(T...)
{
static if (is(T[0]))
alias S = T[0];
else
alias S = typeof(T[0]);

static if (is(S : E[n], E, size_t n) && S.length)
{
enum bool hasElaborateDestructor = hasElaborateDestructor!E;
}
else static if (is(S == struct))
{
enum hasElaborateDestructor = __traits(hasMember, S, "__dtor")
|| anySatisfy!(.hasElaborateDestructor, S.tupleof);
}
else
enum bool hasElaborateDestructor = false;
}

// Somehow fails for non-static nested structs without support for aliases
template hasElaborateCopyConstructor(T...)
{
static if (is(T[0]))
alias S = T[0];
else
alias S = typeof(T[0]);

static if (is(S : E[n], E, size_t n) && S.length)
{
enum bool hasElaborateCopyConstructor = hasElaborateCopyConstructor!E;
}
else static if (is(S == struct))
{
enum hasElaborateCopyConstructor = __traits(hasMember, S, "__postblit")
|| anySatisfy!(.hasElaborateCopyConstructor, S.tupleof);
}
else
enum bool hasElaborateCopyConstructor = false;
}

template staticMap(alias F, T...)
{
static if (T.length == 0)
{
alias staticMap = TypeTuple!();
}
else static if (T.length == 1)
{
alias staticMap = TypeTuple!(F!(T[0]));
}
else
{
alias staticMap =
TypeTuple!(
staticMap!(F, T[ 0 .. $/2]),
staticMap!(F, T[$/2 .. $ ]));
}
}

template isNested(T)
if(is(T == class) || is(T == struct) || is(T == union))
{
enum isNested = __traits(isNested, T);
}

private enum NameOf(alias T) = T.stringof;

template FieldNameTuple(T)
{
static if (is(T == struct) || is(T == union))
alias FieldNameTuple = staticMap!(NameOf, T.tupleof[0 .. $ - isNested!T]);
else static if (is(T == class))
alias FieldNameTuple = staticMap!(NameOf, T.tupleof);
else
alias FieldNameTuple = TypeTuple!"";
}
92 changes: 85 additions & 7 deletions src/object.di
Expand Up @@ -600,6 +600,82 @@ inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
return (*aa).get(key, defaultValue);
}

private void _destructRecurse(S)(ref S s)
if (is(S == struct))
{
import core.internal.traits : hasElaborateDestructor;

static if (__traits(hasMember, S, "__dtor"))
s.__dtor();

foreach_reverse (i, ref field; s.tupleof)
{
static if (hasElaborateDestructor!(typeof(field)))
_destructRecurse(field);
}
}

private void _destructRecurse(E, size_t n)(ref E[n] arr)
{
import core.internal.traits : hasElaborateDestructor;

static if (hasElaborateDestructor!E)
{
foreach_reverse (ref elem; arr)
_destructRecurse(elem);
}
}

private string _genFieldPostblit(S)()
{
import core.internal.traits : hasElaborateCopyConstructor;
import core.internal.traits : FieldNameTuple;

string code;
foreach(fieldName; FieldNameTuple!S)
{
static if(hasElaborateCopyConstructor!(typeof(__traits(getMember, S.init, fieldName))))
{
code ~= `
_postblitRecurse(s.` ~ fieldName ~ `);
scope(failure) _destructRecurse(s. ` ~ fieldName ~ `);
`;
}
}
return code;
}

// Public and explicitly undocumented
void _postblitRecurse(S)(ref S s)
if (is(S == struct))
{
mixin(_genFieldPostblit!S());

static if (__traits(hasMember, S, "__postblit"))
s.__postblit();
}

// Ditto
void _postblitRecurse(E, size_t n)(ref E[n] arr)
{
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]);
}
}

void destroy(T)(T obj) if (is(T == class))
{
rt_finalize(cast(void*)obj);
Expand All @@ -612,13 +688,15 @@ void destroy(T)(T obj) if (is(T == interface))

void destroy(T)(ref T obj) if (is(T == struct))
{
typeid(T).destroy(&obj);
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
auto init = cast(ubyte[])typeid(T).init();
if(init.ptr is null) // null ptr means initialize to 0s
buf[] = 0;
else
buf[] = init[];
_destructRecurse(obj);
() @trusted {
auto buf = (cast(ubyte*) &obj)[0 .. T.sizeof];
auto init = cast(ubyte[])typeid(T).init();
if (init.ptr is null) // null ptr means initialize to 0s
buf[] = 0;
else
buf[] = init[];
} ();
}

void destroy(T : U[n], U, size_t n)(ref T obj) if (!is(T == struct))
Expand Down

0 comments on commit 6d6aa3d

Please sign in to comment.