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