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, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 // a thread-safe weak reference implementation
18 // http://forum.dlang.org/thread/jjote0$1cql$1@digitalmars.com
19 module iv
.weakref
/*is aliced*/;
21 import core
.atomic
, core
.memory
;
25 private alias void delegate (Object
) DEvent
;
26 private extern (C
) void rt_attachDisposeEvent (Object h
, DEvent e
);
27 private extern (C
) void rt_detachDisposeEvent (Object h
, DEvent e
);
29 final class Weak(T
: Object
) {
30 enum PointerMask
= 0xa5a5a5a5u
;
32 // Note: This class uses a clever trick which works fine for
33 // a conservative GC that was never intended to do
34 // compaction/copying in the first place. However, if compaction is
35 // ever added to D's GC, this class will break horribly. If D ever
36 // gets such a GC, we should push strongly for built-in weak
39 private usize mObject
;
43 this (T obj
=null) @trusted { hook(obj
); }
45 @property T
object () const nothrow @trusted {
46 auto obj
= cast(T
)cast(void*)(atomicLoad(*cast(shared)&mObject
)^PointerMask
);
47 // we've moved obj into the GC-scanned stack space, so it's now
48 // safe to ask the GC whether the object is still alive.
49 // note that even if the cast and assignment of the obj local
50 // doesn't put the object on the stack, this call will.
51 // so, either way, this is safe.
52 if (obj
!is null && GC
.addrOf(cast(void*)obj
)) return obj
;
56 @property void object (T obj
) @trusted {
57 auto oobj
= cast(T
)cast(void*)(atomicLoad(*cast(shared)&mObject
)^PointerMask
);
58 if (oobj
!is null && GC
.addrOf(cast(void*)oobj
)) unhook(oobj
);
63 @property bool empty () const pure nothrow @trusted { pragma(inline
, true); return (object
is null); }
65 void clear () @trusted { object
= null; }
67 void opAssign (T obj
) @trusted { object
= obj
; }
69 private void hook (Object obj
) @trusted {
71 //auto ptr = cast(usize)cast(void*)obj;
72 // fix from Andrej Mitrovic
73 auto ptr
= cast(usize
)*(cast(void**)&obj
);
75 // we use atomics because not all architectures may guarantee atomic store and load of these values
76 atomicStore(*cast(shared)&mObject
, ptr
);
77 // only assigned once, so no atomics
79 mHash
= typeid(T
).getHash(&obj
);
80 rt_attachDisposeEvent(obj
, &unhook
);
81 GC
.setAttr(cast(void*)this, GC
.BlkAttr
.NO_SCAN
);
83 atomicStore(*cast(shared)&mObject
, cast(usize
)0^PointerMask
);
87 private void unhook (Object obj
) @trusted {
88 rt_detachDisposeEvent(obj
, &unhook
);
89 // this assignment is important.
90 // if we don't null mObject when it is collected, the check
91 // in object could return false positives where the GC has
92 // reused the memory for a new object.
93 atomicStore(*cast(shared)&mObject
, cast(usize
)0^PointerMask
);
96 override bool opEquals (Object o
) nothrow @trusted {
97 if (this is o
) return true;
98 if (auto weak
= cast(Weak
!T
)o
) return (mPtr
== weak
.mPtr
);
102 override int opCmp (Object o
) nothrow @trusted {
103 if (auto weak
= cast(Weak
!T
)o
) return (mPtr
> weak
.mPtr ?
1 : mPtr
< weak
.mPtr ?
-1 : 0);
107 override usize
toHash () nothrow @trusted {
109 return (obj ?
typeid(T
).getHash(&obj
) : mHash
);
112 override string
toString () {
114 return (obj ? obj
.toString() : toString());
119 version(weakref_test
) unittest {
125 this (int nn
) @trusted nothrow { n
= nn
; }
126 ~this () @trusted @nogc { import core
.stdc
.stdio
: printf
; printf("A:~this()\n"); }
130 //auto wr = new Weak!A(a);
131 Weak
!A wr
= new Weak
!A(a
);
132 writefln("w=%s", wr
.empty
);
135 writefln("w=%s", wr
.empty
);
137 writefln("w=%s", wr
.empty
);
142 writefln("w=%s", wr
.empty
);
145 writefln("w=%s", wr
.empty
);
149 writefln("w=%s", wr
.empty
);
152 writefln("w=%s", wr
.empty
);