1
module automem.utils;
2

3
import std.traits : isStaticArray;
4

5
// This is a destroy() copied and modified from
6
// druntime, to allow for destruction attribute inference
7

8
void destruct(T)(T obj) if (is(T == class)) {
9 2
    (cast(_finalizeType!T) &rt_finalize)(() @trusted { return cast(void*) obj; }());
10
}
11

12
void destruct(T)(T obj) if (is(T == interface)) {
13
    destruct(cast(Object) obj);
14
}
15

16
void destruct(T)(ref T obj) if (is(T == struct)) {
17
    static if (__traits(hasMember, T, "__xdtor") &&
18
               __traits(isSame, T, __traits(parent, obj.__xdtor)))
19 2
        obj.__xdtor;
20
}
21

22
void destruct(T : U[n], U, size_t n)(ref T obj) if (!is(T == struct)) {
23
    foreach_reverse (ref e; obj[])
24
        destruct(e);
25
}
26

27
void destruct(T)(ref T obj)
28
if(!is(T == struct) && !is(T == class) && !is(T == interface) && !isStaticArray!T) {
29 2
    obj = T.init;
30
}
31

32
@("class dtor inference")
33
@safe @nogc pure unittest {
34
    class A { ~this() @nogc {} }
35
    class B : A { ~this() {} }
36
    class C : B { ~this() @nogc {} }
37

38
    static assert( __traits(compiles, () @nogc { A a; destruct(a); }));
39
    static assert(!__traits(compiles, () @nogc { B a; destruct(b); }));
40
    static assert(!__traits(compiles, () @nogc { C a; destruct(c); }));
41
}
42

43
@("class dtor inference with struct members")
44
@system @nogc pure unittest {
45
    import std.traits: functionAttributes, FunctionAttribute;
46
    import std.conv: text;
47

48
    struct A { ~this() @nogc {} }
49 0
    struct B { ~this() { new int; } }
50
    class CA { A a; ~this() @nogc {} }
51
    class CB { B b; ~this() @nogc {} }
52

53
    static assert( __traits(compiles, () @nogc { CA a; destruct(a); }));
54
    static assert(!__traits(compiles, () @system @nogc { CB b; destruct(b); }));
55
}
56

57
private:
58

59
extern(C) void rt_finalize(void* p, bool det = true) @trusted @nogc pure;
60

61
// A slightly better hack than the one presented by
62
// https://www.auburnsounds.com/blog/2016-11-10_Running-D-without-its-runtime.html
63
//
64
// This template infers destruction attributes from the given
65
// class hierarchy. It actually may be incorrect, as by
66
// the current language rules derived class can still
67
// have weaker set of destruction attributes.
68
extern(C)
69
template _finalizeType(T) {
70
    import std.traits: Unqual;
71
    static if (is(Unqual!T == Object)) {
72
        alias _finalizeType = typeof(&rt_finalize);
73
    } else {
74
        import std.traits : BaseClassesTuple;
75
        import std.meta : AliasSeq;
76
        alias _finalizeType = typeof(function void(void* p, bool det = true) {
77
            // generate a body that calls all the destructors in the chain,
78
            // compiler should infer the intersection of attributes
79
            foreach (B; AliasSeq!(T, BaseClassesTuple!T)) {
80
                // __dtor, i.e. B.~this
81
                static if (__traits(hasMember, B, "__dtor"))
82
                    () { B obj; obj.__dtor; } ();
83
                // __xdtor, i.e. dtors for all RAII members
84
                static if (__traits(hasMember, B, "__xdtor"))
85
                    () { B obj; obj.__xdtor; } ();
86
            }
87
        });
88
    }
89
}

Read our documentation on viewing source code .

Loading