1 /* Invisible Vector Library
2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 // a thread-safe weak reference implementation
19 // http://forum.dlang.org/thread/jjote0$1cql$1@digitalmars.com
20 module iv
.weakref
/*is aliced*/;
22 import core
.atomic
, core
.memory
;
26 private alias void delegate (Object
) DEvent
;
27 private extern (C
) void rt_attachDisposeEvent (Object h
, DEvent e
);
28 private extern (C
) void rt_detachDisposeEvent (Object h
, DEvent e
);
30 final class Weak(T
: Object
) {
31 enum PointerMask
= 0xa5a5a5a5u
;
33 // Note: This class uses a clever trick which works fine for
34 // a conservative GC that was never intended to do
35 // compaction/copying in the first place. However, if compaction is
36 // ever added to D's GC, this class will break horribly. If D ever
37 // gets such a GC, we should push strongly for built-in weak
40 private usize mObject
;
44 this (T obj
=null) @trusted { hook(obj
); }
46 @property T
object () const nothrow @trusted {
47 auto obj
= cast(T
)cast(void*)(atomicLoad(*cast(shared)&mObject
)^PointerMask
);
48 // we've moved obj into the GC-scanned stack space, so it's now
49 // safe to ask the GC whether the object is still alive.
50 // note that even if the cast and assignment of the obj local
51 // doesn't put the object on the stack, this call will.
52 // so, either way, this is safe.
53 if (obj
!is null && GC
.addrOf(cast(void*)obj
)) return obj
;
57 @property void object (T obj
) @trusted {
58 auto oobj
= cast(T
)cast(void*)(atomicLoad(*cast(shared)&mObject
)^PointerMask
);
59 if (oobj
!is null && GC
.addrOf(cast(void*)oobj
)) unhook(oobj
);
64 @property bool empty () const pure nothrow @trusted { pragma(inline
, true); return (object
is null); }
66 void clear () @trusted { object
= null; }
68 void opAssign (T obj
) @trusted { object
= obj
; }
70 private void hook (Object obj
) @trusted {
72 //auto ptr = cast(usize)cast(void*)obj;
73 // fix from Andrej Mitrovic
74 auto ptr
= cast(usize
)*(cast(void**)&obj
);
76 // we use atomics because not all architectures may guarantee atomic store and load of these values
77 atomicStore(*cast(shared)&mObject
, ptr
);
78 // only assigned once, so no atomics
80 mHash
= typeid(T
).getHash(&obj
);
81 rt_attachDisposeEvent(obj
, &unhook
);
82 GC
.setAttr(cast(void*)this, GC
.BlkAttr
.NO_SCAN
);
84 atomicStore(*cast(shared)&mObject
, cast(usize
)0^PointerMask
);
88 private void unhook (Object obj
) @trusted {
89 rt_detachDisposeEvent(obj
, &unhook
);
90 // this assignment is important.
91 // if we don't null mObject when it is collected, the check
92 // in object could return false positives where the GC has
93 // reused the memory for a new object.
94 atomicStore(*cast(shared)&mObject
, cast(usize
)0^PointerMask
);
97 override bool opEquals (Object o
) nothrow @trusted {
98 if (this is o
) return true;
99 if (auto weak
= cast(Weak
!T
)o
) return (mPtr
== weak
.mPtr
);
103 override int opCmp (Object o
) nothrow @trusted {
104 if (auto weak
= cast(Weak
!T
)o
) return (mPtr
> weak
.mPtr ?
1 : mPtr
< weak
.mPtr ?
-1 : 0);
108 override usize
toHash () nothrow @trusted {
110 return (obj ?
typeid(T
).getHash(&obj
) : mHash
);
113 override string
toString () {
115 return (obj ? obj
.toString() : toString());
120 version(weakref_test
) unittest {
126 this (int nn
) @trusted nothrow { n
= nn
; }
127 ~this () @trusted @nogc { import core
.stdc
.stdio
: printf
; printf("A:~this()\n"); }
131 //auto wr = new Weak!A(a);
132 Weak
!A wr
= new Weak
!A(a
);
133 writefln("w=%s", wr
.empty
);
136 writefln("w=%s", wr
.empty
);
138 writefln("w=%s", wr
.empty
);
143 writefln("w=%s", wr
.empty
);
146 writefln("w=%s", wr
.empty
);
150 writefln("w=%s", wr
.empty
);
153 writefln("w=%s", wr
.empty
);