Update
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 |
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 .