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 (cast(_finalizeType!T)&rt_finalize)(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 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 obj = T.init; 30 } 31 32 @("class dtor inference") 33 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 unittest { 45 struct A { ~this() @nogc {} } 46 struct B { ~this() {} } 47 class CA { A a; ~this() @nogc {} } 48 class CB { B b; ~this() @nogc {} } 49 50 static assert( __traits(compiles, () @nogc { CA a; destruct(a); })); 51 static assert(!__traits(compiles, () @nogc { CB a; destruct(b); })); 52 } 53 54 private: 55 56 extern(C) void rt_finalize(void* p, bool det = true); 57 58 // A slightly better hack than the one presented by 59 // https://www.auburnsounds.com/blog/2016-11-10_Running-D-without-its-runtime.html 60 // 61 // This template infers destruction attributes from the given 62 // class hierarchy. It actually may be incorrect, as by 63 // the current language rules derived class can still 64 // have weaker set of destruction attributes. 65 extern(C) 66 template _finalizeType(T) { 67 static if (is(T == Object)) { 68 alias _finalizeType = typeof(&rt_finalize); 69 } else { 70 import std.traits : BaseClassesTuple; 71 import std.meta : AliasSeq; 72 alias _finalizeType = typeof((void* p, bool det = true) { 73 // generate a body that calls all the destructors in the chain, 74 // compiler should infer the intersection of attributes 75 foreach (B; AliasSeq!(T, BaseClassesTuple!T)) { 76 // __dtor, i.e. B.~this 77 static if (__traits(hasMember, B, "__dtor")) 78 () { B obj; obj.__dtor; } (); 79 // __xdtor, i.e. dtors for all RAII members 80 static if (__traits(hasMember, B, "__xdtor")) 81 () { B obj; obj.__xdtor; } (); 82 } 83 }); 84 } 85 } 86