root/trunk/weakref/weakref.d

Revision 238, 3.2 kB (checked in by baxissimo, 10 months ago)

Weak reference class.

Line 
1 /*==========================================================================
2  * weakref.d
3  *    Written in the D Programming Language (http://www.digitalmars.com/d)
4  */
5 /***************************************************************************
6  * Creates a weak reference to a class instance.
7  *
8  * A weak reference lets you hold onto a pointer to an object without
9  * preventing the garbage collector from collecting it.
10  * If the garbage collector collects the object then the weak pointer will
11  * become 'null'.  Thus one should always check a weak pointer for null
12  * before doing anything that depends upon it having a value.
13  *
14  * Tested with:
15  *    DMD 1.025 / Phobos 1.025
16  *    DMD 1.025 / Tango 0.99.4
17  *
18  * Usage example:
19 ---
20  class Something {}
21
22  auto a = new Something();
23  auto wa = new WeakRef!(Something)(a);
24  std.gc.fullCollect();
25     
26  // Reference 'a' prevents collection so wa.ptr is non-null
27  assert(wa.ptr is a);
28
29  delete a;
30  
31  // 'a' is gone now, so wa.ptr magically becomes null
32  assert(wa.ptr is null);
33 ---
34  *   
35  *
36  * Author:  William V. Baxter III
37  * Contributors:
38  * Date: 21 Jan 2008
39  * Copyright: (C) 2008  William Baxter
40  * License: Public Domain where allowed by law, ZLIB/PNG otherwise.
41  */
42 //===========================================================================
43
44 module weakref;
45
46 version(Tango) {
47     private {
48         alias void delegate(Object) DisposeEvt;
49         extern (C) void  rt_attachDisposeEvent( Object obj, DisposeEvt evt );
50         extern (C) void  rt_detachDisposeEvent( Object obj, DisposeEvt evt );
51     }
52 }
53
54 class WeakRef(T : Object) {
55 private:
56     size_t cast_ptr_;
57     void unhook(Object o) {
58         if (cast(size_t)cast(void*)o == cast_ptr_) {
59             version(Tango) {
60                 rt_detachDisposeEvent(o, &unhook);
61             } else {
62                 o.notifyUnRegister(&unhook);
63             }
64             cast_ptr_ = 0;
65         }
66     }
67 public:
68
69     this(T tptr) {
70         cast_ptr_ = cast(size_t)cast(void*)tptr;
71         version(Tango) {
72             rt_attachDisposeEvent(tptr, &unhook);
73         } else {
74             tptr.notifyRegister(&unhook);
75         }
76     }
77     ~this() {
78         T p = ptr();
79         if (p) {
80             version(Tango) {
81                 rt_detachDisposeEvent(p, &unhook);
82             } else {
83                 p.notifyUnRegister(&unhook);
84             }
85         }
86     }
87     T ptr() {
88         return cast(T)cast(void*)cast_ptr_;
89     }
90     WeakRef dup() {
91         return new WeakRef(ptr());
92     }
93 }
94
95
96 version(UnitTest) {
97
98 version(Tango) {
99     import tango.core.Memory;
100     alias GC.collect collect;
101 } else {
102     static import std.gc;
103     alias std.gc.fullCollect collect;
104 }
105
106 unittest {
107     class Something {
108         int value;
109         this(int v) { value = v; }
110         ~this() { value = -1; }
111     }
112
113     WeakRef!(Something) wa;
114
115     auto a = new Something(1);
116     wa = new WeakRef!(Something)(a);
117     assert(a is wa.ptr);
118
119     collect();
120     assert(a is wa.ptr);
121
122     delete a;
123
124     // a now gone so should be collected
125     collect();
126    
127     assert(wa.ptr is null);
128 }
129 }
130 //--- Emacs setup ---
131 // Local Variables:
132 // c-basic-offset: 4
133 // indent-tabs-mode: nil
134 // End:
Note: See TracBrowser for help on using the browser.