1 /*
2 * Hunt - A refined core library for D programming language.
3 *
4 * Copyright (C) 2018-2019 HuntLabs
5 *
6 * Website: https://www.huntlabs.net/
7 *
8 * Licensed under the Apache-2.0 License.
9 *
10 */11 12 modulehunt.util.WeakReference;
13 14 /**
15 * This module implements weak references.
16 *
17 * Authors: Alex Rønne Petersen, w0rp
18 *
19 * Credit and thanks goes to Alex Rønne Petersen for implementing
20 * another weak reference type. This type is pretty much a fork of his
21 * code, some of it still surviving.
22 */23 24 importcore.memory;
25 importcore.atomic;
26 27 privatealiasvoiddelegate(Object) DEvent;
28 privateextern (C) voidrt_attachDisposeEvent(Objecth, DEvente);
29 privateextern (C) voidrt_detachDisposeEvent(Objecth, DEvente);
30 31 privatealiasextern (C) voidfunction(Object, DEvent) @systempurenothrowPureEventFunc;
32 33 /**
34 * This class implements a weak reference wrapper for class T.
35 *
36 * A weak reference will not prevent the object from being collected
37 * in a garbage collection cycle. If and when the object is collected,
38 * the internal reference to object will become null.
39 *
40 * This weak reference wrapper is thread safe.
41 *
42 * Params:
43 * T = The type of class.
44 *
45 * See_Also:
46 * https://github.com/w0rp/dstruct/blob/master/source/dstruct/weak_reference.d
47 * https://forum.dlang.org/post/kd03f2$26ju$1@digitalmars.com
48 */49 classWeakReference(T) if (is(T == class) || is(T == interface)) {
50 privatesharedsize_t_ptr;
51 52 @trustedpurenothrowprivatevoidfreeWrapper() {
53 if (_ptr == 0) {
54 // We already cleaned up, don't do it again.55 return;
56 }
57 58 // Detach the previously attached dispose event, it is done.59 (cast(PureEventFunc)&rt_detachDisposeEvent)(cast(Object) cast(void*) _ptr, &disposed);
60 61 // Set the invalid pointer to null so we know it's gone.62 atomicStore(_ptr, cast(size_t) 0);
63 }
64 65 privatevoiddisposed(Object) {
66 freeWrapper();
67 }
68 69 /**
70 * Create a weak reference wrapper for a given object.
71 *
72 * Params:
73 * object = The object to hold a reference to.
74 */75 @trustedpurenothrowthis(Tobject) {
76 if (objectisnull) {
77 // No work needs to be done for null.78 return;
79 }
80 81 // Set the pointer atomically in a size_t so it's not a valid pointer.82 // Use cast(void**) to avoid opCast problems.83 atomicStore(_ptr, cast(size_t) cast(void**) object);
84 85 // Stop the GC from scanning inside this class.86 // This will make the interior reference a weak reference.87 GC.setAttr(cast(void*) this, GC.BlkAttr.NO_SCAN);
88 89 // Call a special D runtime function for nulling our reference90 // to the object when the object is destroyed.91 (cast(PureEventFunc)&rt_attachDisposeEvent)(cast(Object) object, &disposed);
92 }
93 94 @trustedpurenothrow ~this() {
95 freeWrapper();
96 }
97 98 /**
99 * Return the referenced object held in this weak reference wrapper.
100 * If and when the object is collected, this function will return null.
101 *
102 * Returns: The referenced object.
103 */104 @trustedpurenothrowTget() inout {
105 autoptr = cast(void*) atomicLoad(_ptr);
106 107 // Check if the object is still alive before we return it.108 // It might be killed in another thread.109 returnGC.addrOf(ptr) ? cast(T) ptr : null;
110 }
111 112 /**
113 * Params:
114 * other = Another object.
115 *
116 * Returns: True the other object is a weak reference to the same object.
117 */118 @safepurenothrowoverrideboolopEquals(Objectother) {
119 if (otheristhis) {
120 returntrue;
121 }
122 123 if (autootherWeak = cast(WeakReference!T) other) {
124 return_ptr == otherWeak._ptr;
125 }
126 127 returnfalse;
128 }
129 130 /// ditto131 // @trusted pure nothrow bool opEquals(const(Object) other) {132 // return this.opEquals(cast(Object) other);133 // }134 }
135 136 /**
137 * This is a convenience function for creating a new
138 * weak reference wrapper for a given object.
139 *
140 * Params:
141 * object = The object to create a reference for.
142 *
143 * Returns: A new weak reference to the given object.
144 */145 WeakReference!Tweak(T)(Tobject) if (is(T == class)) {
146 returnnewWeakReference!T(object);
147 }
148 149 // Test that the reference is held.150 unittest {
151 classSomeType {
152 }
153 154 SomeTypex = newSomeType();
155 autoy = weak(x);
156 157 assert(y.get() isx);
158 }
159 160 // Test that the reference is removed when the object is destroyed.161 unittest {
162 classSomeType {
163 }
164 165 SomeTypex = newSomeType();
166 autoy = weak(x);
167 168 destroy(x);
169 170 assert(y.get() isnull);
171 }
172 173 // Test equality based on the reference held in the wrappers.174 // BUG: Reported defects -@zxp at 1/11/2019, 10:24:21 AM175 // https://github.com/w0rp/dstruct/issues/2176 // unittest {177 // class SomeType {178 // }179 180 // SomeType x = new SomeType();181 // auto y = weak(x);182 // auto z = weak(x);183 184 // // assert(y !is z);185 // // assert(y == z);186 187 // }188 189 // Test equality after nulling things.190 // unittest {191 // class SomeType {192 // }193 194 // SomeType x = new SomeType();195 // auto y = weak(x);196 // auto z = weak(x);197 198 // destroy(x);199 200 // assert(y !is z);201 // // BUG: Reported defects -@zxp at 1/7/2019, 4:59:31 PM202 // // 203 // // assert(y == z); // bug204 // }205 206 // Test tail-const weak references.207 unittest {
208 classSomeType {
209 }
210 211 constx = newSomeType();
212 consty = newSomeType();
213 214 autoz = weak(x);
215 z = weak(y);
216 }