some updates
[iv.d.git] / weakref.d
blob781151b03bc64b6e9187b9a54a9ac052c41a1100
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;
22 import iv.alice;
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
37 // references.
39 private usize mObject;
40 private usize mPtr;
41 private usize mHash;
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;
53 return null;
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);
59 oobj = null;
60 hook(obj);
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 {
70 if (obj !is null) {
71 //auto ptr = cast(usize)cast(void*)obj;
72 // fix from Andrej Mitrovic
73 auto ptr = cast(usize)*(cast(void**)&obj);
74 ptr ^= PointerMask;
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
78 mPtr = ptr;
79 mHash = typeid(T).getHash(&obj);
80 rt_attachDisposeEvent(obj, &unhook);
81 GC.setAttr(cast(void*)this, GC.BlkAttr.NO_SCAN);
82 } else {
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);
99 return false;
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);
104 return 1;
107 override usize toHash () nothrow @trusted {
108 auto obj = object;
109 return (obj ? typeid(T).getHash(&obj) : mHash);
112 override string toString () {
113 auto obj = object;
114 return (obj ? obj.toString() : toString());
119 version(weakref_test) unittest {
120 import core.memory;
121 import std.stdio;
123 static class A {
124 int n;
125 this (int nn) @trusted nothrow { n = nn; }
126 ~this () @trusted @nogc { import core.stdc.stdio : printf; printf("A:~this()\n"); }
129 auto a = new A(42);
130 //auto wr = new Weak!A(a);
131 Weak!A wr = new Weak!A(a);
132 writefln("w=%s", wr.empty);
133 assert(!wr.empty);
134 delete a;
135 writefln("w=%s", wr.empty);
136 GC.collect();
137 writefln("w=%s", wr.empty);
138 assert(wr.empty);
140 a = new A(666);
141 wr.object = a;
142 writefln("w=%s", wr.empty);
143 assert(!wr.empty);
144 wr.clear();
145 writefln("w=%s", wr.empty);
146 assert(wr.empty);
148 wr = a;
149 writefln("w=%s", wr.empty);
150 assert(!wr.empty);
151 wr.object = null;
152 writefln("w=%s", wr.empty);
153 assert(wr.empty);