1 module des.util.arch.emm; 2 3 import des.util.arch.tree; 4 5 import des.util.testsuite; 6 7 /// 8 interface ExternalMemoryManager : TNode!(ExternalMemoryManager,"","EMM") 9 { 10 protected 11 { 12 /// 13 @property void isDestroyed( bool d ); 14 15 /// 16 void selfConstruct(); 17 /// 18 void selfDestroy(); 19 /// 20 void preChildsDestroy(); 21 } 22 23 /// 24 @property bool isDestroyed() const; 25 26 final 27 { 28 /// 29 T registerChildEMM(T)( T obj, bool if_orphan=false ) 30 if( is( T == class ) || is( T == interface ) ) 31 { 32 if( auto cemm = cast(ExternalMemoryManager)obj ) 33 if( ( if_orphan && cemm.parentEMM is null ) || !if_orphan ) 34 attachChildsEMM( cemm ); 35 return obj; 36 } 37 38 /// 39 T[] registerChildEMM(T)( T[] objs, bool if_orphan=false ) 40 if( is( T == class ) || is( T == interface ) ) 41 { 42 foreach( obj; objs ) 43 registerChildEMM( obj, if_orphan ); 44 return objs; 45 } 46 47 /// 48 T newEMM(T,Args...)( Args args ) 49 { return registerChildEMM( new T(args) ); } 50 51 /// 52 void destroy() 53 { 54 if( isDestroyed ) return; 55 preChildsDestroy(); 56 foreach( cemm; childsEMM ) 57 cemm.destroy(); 58 selfDestroy(); 59 isDestroyed = true; 60 } 61 } 62 63 /// 64 mixin template EMM(string file=__FILE__,size_t line=__LINE__) 65 { 66 static if( !is(typeof(__EMM_BASE_IMPLEMENT)) ) 67 { 68 protected enum __EMM_BASE_IMPLEMENT = true; 69 70 mixin TNodeHelperEMM!(true,true); 71 72 private bool is_destroyed = false; 73 public final bool isDestroyed() const { return is_destroyed; } 74 protected final void isDestroyed( bool d ) 75 { 76 bool change = is_destroyed != d; 77 is_destroyed = d; 78 if( change && !is_destroyed ) 79 selfConstruct(); 80 } 81 82 import std.traits; 83 84 protected override 85 { 86 static if( isAbstractFunction!selfConstruct ) void selfConstruct() {} 87 static if( isAbstractFunction!selfDestroy ) void selfDestroy() {} 88 static if( isAbstractFunction!preChildsDestroy ) void preChildsDestroy() {} 89 } 90 } 91 else 92 { 93 version(emmcheck) 94 pragma(msg, format( "WARNING: duplicate mixin EMM at %s:%d", file, line ) ); 95 } 96 } 97 } 98 99 unittest 100 { 101 string[] log; 102 103 class Test : ExternalMemoryManager 104 { 105 mixin EMM; 106 string name; 107 this( string name ) { this.name = name; } 108 protected: 109 void preChildsDestroy() 110 { log ~= name ~ ".preChildsDestroy"; } 111 void selfDestroy() 112 { log ~= name ~ ".selfDestroy"; } 113 } 114 115 auto a = new Test( "a" ); 116 auto b = new Test( "b" ); 117 auto c = new Test( "c" ); 118 auto d = new Test( "d" ); 119 120 assertNull( a.parentEMM ); 121 assertNull( b.parentEMM ); 122 assertNull( c.parentEMM ); 123 assertNull( d.parentEMM ); 124 125 assertNull( a.childsEMM ); 126 assertNull( b.childsEMM ); 127 assertNull( c.childsEMM ); 128 assertNull( d.childsEMM ); 129 130 a.registerChildEMM( b ); 131 assertEq( a.childsEMM.length, 1 ); 132 assertEq( a.childsEMM[0], b ); 133 assertEq( b.parentEMM, a ); 134 135 c.registerChildEMM( b ); 136 assertEq( a.childsEMM.length, 0 ); 137 assertEq( c.childsEMM.length, 1 ); 138 assertEq( c.childsEMM[0], b ); 139 assertEq( b.parentEMM, c ); 140 141 a.registerChildEMM( b, true ); 142 assertEq( a.childsEMM.length, 0 ); 143 assertEq( c.childsEMM.length, 1 ); 144 assertEq( c.childsEMM[0], b ); 145 assertEq( b.parentEMM, c ); 146 147 a.registerChildEMM( b ); 148 assertEq( a.childsEMM.length, 1 ); 149 assertEq( a.childsEMM[0], b ); 150 assertEq( b.parentEMM, a ); 151 assertEq( c.childsEMM.length, 0 ); 152 153 mustExcept({ b.registerChildEMM( a ); }); 154 155 a.registerChildEMM( d ); 156 assertEq( a.childsEMM.length, 2 ); 157 assertEq( a.childsEMM[1], d ); 158 159 d.destroy(); 160 assertEq( a.childsEMM.length, 2 ); 161 assertEq( log, [ "d.preChildsDestroy", "d.selfDestroy" ] ); 162 163 assertNull( c.parentEMM ); 164 assertNull( c.childsEMM ); 165 166 a.destroy(); 167 assertEq( log, [ "d.preChildsDestroy", 168 "d.selfDestroy", 169 "a.preChildsDestroy", 170 "b.preChildsDestroy", 171 "b.selfDestroy", 172 "a.selfDestroy" 173 ] ); 174 }