1 module yu.memory.sharedref; 2 3 import core.atomic; 4 import std.experimental.allocator; 5 import std.experimental.allocator.mallocator : Mallocator; 6 import std.experimental.allocator.building_blocks.free_list : SharedFreeList; 7 8 static import std.algorithm; 9 static import std.algorithm.mutation; 10 import std.traits; 11 import yu.traits : isInheritClass, Pointer; 12 13 struct ISharedRef(Allocator, T, bool Shared = true) { 14 enum isSaticAlloc = (stateSize!Allocator == 0); 15 static if (isSaticAlloc) 16 alias Alloc = typeof(Allocator.instance); 17 else 18 alias Alloc = Allocator; 19 20 enum isShared = Shared || is(T == shared); 21 enum isSharedRef = true; 22 alias ValueType = Pointer!T; 23 alias Deleter = void function(ref Alloc, ValueType); 24 alias Data = ExternalRefCountData!(Alloc, isShared); 25 alias DataWithDeleter = ExternalRefCountDataWithDeleter!(Alloc, ValueType, isShared); 26 alias TWeakRef = IWeakRef!(Allocator, T, Shared); 27 alias TSharedRef = ISharedRef!(Allocator, T, Shared); 28 29 static if (isSaticAlloc) { 30 this(ValueType ptr) { 31 internalConstruct(ptr, &defaultDeleter); 32 } 33 34 this(ValueType ptr, Deleter deleter) { 35 internalConstruct(ptr, deleter); 36 } 37 } else { 38 this(Alloc alloc, ValueType ptr) { 39 _alloc = alloc; 40 internalConstruct(ptr, &defaultDeleter); 41 } 42 43 this(Alloc alloc, ValueType ptr, Deleter deleter) { 44 _alloc = alloc; 45 internalConstruct(ptr, deleter); 46 } 47 48 @property Alloc allocator() nothrow { 49 return _alloc; 50 } 51 } 52 53 this(this){ 54 if (_dd) { 55 _dd.strongRef(); 56 _dd.weakRef(); 57 } 58 } 59 60 this(WEAK)(auto ref WEAK wptr) 61 if(is(WEAK == struct) && WEAK.isWeakRef && __traits(isSame, WEAK.Data, Data)) 62 { 63 internalSet(wptr._dd, wptr._alloc, cast(ValueType)wptr._ptr); 64 } 65 66 ~this() { 67 deref(); 68 } 69 70 alias data this; 71 72 @property ValueType data() nothrow { 73 return _ptr; 74 } 75 76 @property bool isNull() const nothrow { 77 return (_ptr is null); 78 } 79 80 pragma(inline) void swap(ref TSharedRef tref) { 81 std.algorithm.mutation.swap(tref._dd, this._dd); 82 std.algorithm.mutation.swap(tref._ptr, this._ptr); 83 static if (!isSaticAlloc) 84 std.algorithm.mutation.swap(tref._alloc, this._alloc); 85 } 86 87 pragma(inline, true) void rest() { 88 clear(); 89 } 90 91 pragma(inline) void clear() { 92 TSharedRef copy = TSharedRef.init; 93 swap(copy); 94 } 95 96 static if (isSaticAlloc) { 97 pragma(inline, true) void rest()(ValueType ptr) { 98 TSharedRef copy = TSharedRef(ptr); 99 swap(copy); 100 } 101 102 pragma(inline, true) void rest()(ValueType ptr, Deleter deleter) { 103 TSharedRef copy = TSharedRef(ptr, deleter); 104 swap(copy); 105 } 106 } else { 107 pragma(inline, true) void rest()(Alloc alloc, ValueType ptr) { 108 TSharedRef copy = TSharedRef(alloc, ptr); 109 swap(copy); 110 } 111 112 pragma(inline, true) void rest()(Alloc alloc, ValueType ptr, Deleter deleter) { 113 TSharedRef copy = TSharedRef(alloc, ptr, deleter); 114 swap(copy); 115 } 116 } 117 118 TWeakRef toWeakRef() { 119 return TWeakRef(this); 120 } 121 122 auto castTo(U)() { 123 ISharedRef!(Alloc, U, isShared) result; 124 if (isNull) 125 return result; 126 alias CastType = Pointer!U; 127 CastType u = cast(CastType) _ptr; 128 if (u !is null) 129 result.internalSet(_dd, _alloc, u); 130 return result; 131 } 132 133 void opAssign(THIS)(auto ref THIS rv)if(is(THIS : typeof(this))){ 134 if(rv._dd is _dd) return; 135 auto copy = cast(typeof(this))rv; 136 swap(copy); 137 } 138 139 void opAssign(WEAK)(auto ref WEAK rhs) 140 if(is(WEAK == struct) && WEAK.isWeakRef && __traits(isSame, WEAK.Data, Data)) 141 { 142 internalSet(rhs._dd, rhs._alloc, cast(ValueType)rhs._ptr); 143 } 144 145 static if (isPointer!ValueType) { 146 ref T opUnary(string op)() if (op == "*") { 147 return *_ptr; 148 } 149 } 150 151 private: 152 153 static void defaultDeleter(ref Alloc alloc, ValueType value) { 154 alloc.dispose(value); 155 } 156 157 void deref() { 158 _ptr = null; 159 deref(_dd, _alloc); 160 } 161 162 static void deref(ref Data dd, ref Alloc alloc) { 163 if (!dd) 164 return; 165 if (!dd.strongDef()) { 166 dd.free(alloc); 167 } 168 if (!dd.weakDef()) { 169 scope(exit) dd = null; 170 sharedRefAllocator.dispose(dd); 171 } 172 } 173 174 void internalConstruct(ValueType ptr, Deleter deleter) { 175 _ptr = ptr; 176 if (ptr !is null) { 177 _dd = sharedRefAllocator.make!(DataWithDeleter)(ptr, deleter); 178 static if(hasMember!(T,"__InitializeFromSharedPointer")) { 179 auto tpytr = cast(Unqual!ValueType)(_ptr); 180 tpytr.__InitializeFromSharedPointer(this); 181 } 182 } 183 } 184 185 void internalSet(Data o, ref Alloc alloc, ValueType ptr) { 186 static if (!isSaticAlloc) { 187 Alloc tmpalloc = _alloc; 188 _alloc = alloc; 189 } else { 190 alias tmpalloc = Alloc.instance; 191 } 192 if (o) { 193 if (o.strongref > 0) { 194 o.strongRef(); 195 o.weakRef(); 196 _ptr = ptr; 197 } else { 198 _ptr = null; 199 o = null; 200 } 201 } 202 std.algorithm.mutation.swap(_dd, o); 203 deref(o, tmpalloc); 204 } 205 206 ValueType _ptr; // 207 Data _dd; 208 static if (!isSaticAlloc) 209 Alloc _alloc; 210 else 211 alias _alloc = Alloc.instance; 212 } 213 214 struct IWeakRef(Allocator, T, bool Shared = true) { 215 enum isSaticAlloc = (stateSize!Allocator == 0); 216 static if (isSaticAlloc) 217 alias Alloc = typeof(Allocator.instance); 218 else 219 alias Alloc = Allocator; 220 enum isShared = Shared || is(T == shared); 221 enum isWeakRef = true; 222 alias ValueType = Pointer!T; 223 alias Data = ExternalRefCountData!(Alloc, isShared); 224 alias TWeakRef = IWeakRef!(Allocator, T, Shared); 225 alias TSharedRef = ISharedRef!(Allocator,T, Shared); 226 227 this(SHARED)(auto ref SHARED tref) 228 if(is(SHARED == struct) && SHARED.isSharedRef && __traits(isSame, SHARED.Data, Data)) 229 { 230 this._ptr = cast(ValueType)tref._ptr; 231 this._dd = tref._dd; 232 if (_dd) 233 _dd.weakRef(); 234 static if (!isSaticAlloc) 235 this._alloc = tref._alloc; 236 } 237 238 this(this){ 239 if (_dd) 240 _dd.weakRef(); 241 } 242 243 pragma(inline, true) bool isNull() nothrow { 244 return (_dd is null || _ptr is null || _dd.strongref == 0); 245 } 246 247 pragma(inline, true) ValueType data() nothrow { 248 return isNull() ? null : _ptr; 249 } 250 251 pragma(inline) void clear() { 252 TWeakRef copy = TWeakRef.init; 253 swap(copy); 254 } 255 256 pragma(inline) void swap(ref TWeakRef tref) { 257 std.algorithm.mutation.swap(tref._dd, this._dd); 258 std.algorithm.mutation.swap(tref._ptr, this._ptr); 259 static if (!isSaticAlloc) 260 std.algorithm.mutation.swap(tref._alloc, this._alloc); 261 } 262 263 pragma(inline, true) TSharedRef toStrongRef() { 264 return TSharedRef(this); 265 } 266 267 void opAssign(THIS)(auto ref THIS rv)if(is(THIS : typeof(this))){ 268 if(rv._dd is _dd) return; 269 auto copy = rv; 270 swap(copy); 271 } 272 273 void opAssign(SHARED)(auto ref SHARED rhs) 274 if(is(SHARED == struct) && SHARED.isSharedRef && __traits(isSame, SHARED.Data, Data)) 275 { 276 internalSet(rhs._dd, rhs._alloc, cast(ValueType)rhs._ptr); 277 } 278 279 private: 280 void deref() { 281 _ptr = null; 282 if (!_dd) return; 283 if (!_dd.weakDef()) { 284 scope(exit) _dd = null; 285 sharedRefAllocator.dispose(_dd); 286 } 287 } 288 289 void internalSet(Data o, ref Alloc alloc, ValueType ptr) { 290 if (_dd is o) 291 return; 292 if (o) { 293 o.weakRef(); 294 _ptr = ptr; 295 } 296 if (_dd && !_dd.weakDef()) 297 sharedRefAllocator.dispose(_dd); 298 _dd = o; 299 static if (!isSaticAlloc) 300 _alloc = alloc; 301 } 302 303 ValueType _ptr; // 只为保留指针在栈中,如果指针是GC分配的内存,而ExternalRefCountData非GC的,则不用把非GC内存添加到GC的扫描列表中 304 Data _dd; 305 static if (!isSaticAlloc) 306 Alloc _alloc; 307 else 308 alias _alloc = Alloc.instance; 309 } 310 311 312 private: 313 static shared SharedFreeList!(Mallocator, chooseAtRuntime) sharedRefAllocator; 314 315 abstract class ExternalRefCountData(Alloc, bool isShared) { 316 pragma(inline, true) final int strongDef() nothrow { 317 static if (isShared) 318 return atomicOp!("-=")(_strongref, 1); 319 else 320 return --_strongref; 321 } 322 323 pragma(inline, true) final int strongRef() nothrow { 324 static if (isShared) 325 return atomicOp!("+=")(_strongref, 1); 326 else 327 return ++_strongref; 328 } 329 330 pragma(inline, true) final int weakDef() nothrow { 331 static if (isShared) 332 return atomicOp!("-=")(_weakref, 1); 333 else 334 return --_weakref; 335 } 336 337 pragma(inline, true) final int weakRef() nothrow { 338 static if (isShared) 339 return atomicOp!("+=")(_weakref, 1); 340 else 341 return ++_weakref; 342 } 343 344 pragma(inline, true) final @property int weakref() nothrow { 345 static if (isShared) 346 return atomicLoad(_weakref); 347 else 348 return _weakref; 349 } 350 351 pragma(inline, true) final @property int strongref() nothrow { 352 static if (isShared) 353 return atomicLoad(_strongref); 354 else 355 return _strongref; 356 } 357 358 void free(ref Alloc alloc); 359 360 static if (isShared) { 361 shared int _weakref = 1; 362 shared int _strongref = 1; 363 } else { 364 int _weakref = 1; 365 int _strongref = 1; 366 } 367 } 368 369 final class ExternalRefCountDataWithDeleter(Alloc, ValueType, bool isShared) 370 : ExternalRefCountData!(Alloc, isShared) { 371 //pragma(msg, "is ahsred " ~ isShared.stringof); 372 alias Deleter = void function(ref Alloc, ValueType); 373 374 this(ValueType ptr, Deleter dele) { 375 value = ptr; 376 deleater = dele; 377 } 378 379 override void free(ref Alloc alloc) { 380 if (deleater && value) 381 deleater(alloc, value); 382 deleater = null; 383 value = null; 384 } 385 386 Deleter deleater; 387 ValueType value; 388 }