]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: wx/weakref.h | |
3 | // Purpose: wxWeakRef - Generic weak references for wxWidgets | |
4 | // Author: Arne Steinarson | |
5 | // Created: 27 Dec 07 | |
6 | // RCS-ID: $Id$ | |
7 | // Copyright: (c) 2007 Arne Steinarson | |
8 | // Licence: wxWindows licence | |
9 | ///////////////////////////////////////////////////////////////////////////// | |
10 | ||
11 | #ifndef _WX_WEAKREF_H_ | |
12 | #define _WX_WEAKREF_H_ | |
13 | ||
14 | #include "wx/tracker.h" | |
15 | ||
16 | #include "wx/meta/convertible.h" | |
17 | #include "wx/meta/int2type.h" | |
18 | ||
19 | template <class T> | |
20 | struct wxIsStaticTrackable | |
21 | { | |
22 | enum { value = wxConvertibleTo<T, wxTrackable>::value }; | |
23 | }; | |
24 | ||
25 | // Weak ref implementation when T has wxTrackable as a known base class | |
26 | template <class T> | |
27 | class wxWeakRefStatic : public wxTrackerNode | |
28 | { | |
29 | public: | |
30 | wxWeakRefStatic() : m_pobj(NULL) { } | |
31 | ||
32 | void Release() | |
33 | { | |
34 | // Release old object if any | |
35 | if ( m_pobj ) | |
36 | { | |
37 | // Remove ourselves from object tracker list | |
38 | wxTrackable *pt = static_cast<wxTrackable*>(m_pobj); | |
39 | pt->RemoveNode(this); | |
40 | m_pobj = NULL; | |
41 | } | |
42 | } | |
43 | ||
44 | protected: | |
45 | void Assign(T* pobj) | |
46 | { | |
47 | if ( m_pobj == pobj ) | |
48 | return; | |
49 | ||
50 | Release(); | |
51 | ||
52 | // Now set new trackable object | |
53 | if ( pobj ) | |
54 | { | |
55 | // Add ourselves to object tracker list | |
56 | wxTrackable *pt = static_cast<wxTrackable*>(pobj); | |
57 | pt->AddNode(this); | |
58 | m_pobj = pobj; | |
59 | } | |
60 | } | |
61 | ||
62 | void AssignCopy(const wxWeakRefStatic& wr) | |
63 | { | |
64 | Assign( wr.m_pobj ); | |
65 | } | |
66 | ||
67 | virtual void OnObjectDestroy() | |
68 | { | |
69 | // Tracked object itself removes us from list of trackers | |
70 | wxASSERT( m_pobj!=NULL ); | |
71 | m_pobj = NULL; | |
72 | } | |
73 | ||
74 | T *m_pobj; | |
75 | }; | |
76 | ||
77 | ||
78 | #if !defined(HAVE_PARTIAL_SPECIALIZATION) || !defined(HAVE_TEMPLATE_OVERLOAD_RESOLUTION) | |
79 | #define USE_STATIC_WEAKREF | |
80 | #endif | |
81 | ||
82 | ||
83 | #ifndef USE_STATIC_WEAKREF | |
84 | template<class T,bool use_static> | |
85 | struct wxWeakRefImpl; | |
86 | ||
87 | // Intermediate class, to select the static case above. | |
88 | template <class T> | |
89 | struct wxWeakRefImpl<T, true> : public wxWeakRefStatic<T> | |
90 | { | |
91 | enum { value = 1 }; | |
92 | }; | |
93 | ||
94 | // Weak ref implementation when T does not have wxTrackable as known base class | |
95 | template<class T> | |
96 | struct wxWeakRefImpl<T, false> : public wxTrackerNode | |
97 | { | |
98 | void Release() | |
99 | { | |
100 | // Release old object if any | |
101 | if ( m_pobj ) | |
102 | { | |
103 | // Remove ourselves from object tracker list | |
104 | m_ptbase->RemoveNode(this); | |
105 | m_pobj = NULL; | |
106 | m_ptbase = NULL; | |
107 | } | |
108 | } | |
109 | ||
110 | protected: | |
111 | wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { } | |
112 | ||
113 | // Assign receives most derived class here and can use that | |
114 | template <class TDerived> | |
115 | void Assign( TDerived* pobj ) | |
116 | { | |
117 | AssignHelper( pobj, wxInt2Type<wxIsStaticTrackable<TDerived>::value>() ); | |
118 | } | |
119 | ||
120 | template <class TDerived> | |
121 | void AssignHelper(TDerived* pobj, wxInt2Type<true>) | |
122 | { | |
123 | wxTrackable *ptbase = static_cast<wxTrackable*>(pobj); | |
124 | DoAssign( pobj, ptbase ); | |
125 | } | |
126 | ||
127 | #ifdef HAVE_DYNAMIC_CAST | |
128 | void AssignHelper(T* pobj, wxInt2Type<false>) | |
129 | { | |
130 | // A last way to get a trackable pointer | |
131 | wxTrackable *ptbase = dynamic_cast<wxTrackable*>(pobj); | |
132 | if ( ptbase ) | |
133 | { | |
134 | DoAssign( pobj, ptbase ); | |
135 | } | |
136 | else | |
137 | { | |
138 | wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); | |
139 | ||
140 | Release(); | |
141 | } | |
142 | } | |
143 | #endif // HAVE_DYNAMIC_CAST | |
144 | ||
145 | void AssignCopy(const wxWeakRefImpl& wr) | |
146 | { | |
147 | DoAssign(wr.m_pobj, wr.m_ptbase); | |
148 | } | |
149 | ||
150 | void DoAssign( T* pobj, wxTrackable *ptbase ) { | |
151 | if( m_pobj==pobj ) return; | |
152 | Release(); | |
153 | ||
154 | // Now set new trackable object | |
155 | if( pobj ) | |
156 | { | |
157 | // Add ourselves to object tracker list | |
158 | wxASSERT( ptbase ); | |
159 | ptbase->AddNode( this ); | |
160 | m_pobj = pobj; | |
161 | m_ptbase = ptbase; | |
162 | } | |
163 | } | |
164 | ||
165 | virtual void OnObjectDestroy() | |
166 | { | |
167 | // Tracked object itself removes us from list of trackers | |
168 | wxASSERT( m_pobj!=NULL ); | |
169 | m_pobj = NULL; | |
170 | m_ptbase = NULL; | |
171 | } | |
172 | ||
173 | T *m_pobj; | |
174 | wxTrackable *m_ptbase; | |
175 | }; | |
176 | ||
177 | #endif // #ifndef USE_STATIC_WEAKREF | |
178 | ||
179 | ||
180 | ||
181 | // A weak reference to an object of type T, where T has type wxTrackable | |
182 | // (usually statically but if not dynamic_cast<> is tried). | |
183 | template <class T> | |
184 | class wxWeakRef : public | |
185 | #ifdef USE_STATIC_WEAKREF | |
186 | wxWeakRefStatic<T> | |
187 | #else | |
188 | wxWeakRefImpl<T, wxIsStaticTrackable<T>::value> | |
189 | #endif | |
190 | { | |
191 | public: | |
192 | // Default ctor | |
193 | wxWeakRef() { } | |
194 | ||
195 | // When we have the full type here, static_cast<> will always work | |
196 | // (or give a straight compiler error). | |
197 | template <class TDerived> | |
198 | wxWeakRef(TDerived* pobj) | |
199 | { | |
200 | Assign(pobj); | |
201 | } | |
202 | ||
203 | // We need this copy ctor, since otherwise a default compiler (binary) copy happens | |
204 | wxWeakRef(const wxWeakRef<T>& wr) | |
205 | { | |
206 | Assign(wr.get()); | |
207 | } | |
208 | ||
209 | template <class TDerived> | |
210 | wxWeakRef<T>& operator=(TDerived* pobj) | |
211 | { | |
212 | Assign(pobj); | |
213 | return *this; | |
214 | } | |
215 | ||
216 | wxWeakRef<T>& operator=(const wxWeakRef<T>& wr) | |
217 | { | |
218 | AssignCopy(wr); | |
219 | return *this; | |
220 | } | |
221 | ||
222 | virtual ~wxWeakRef() { this->Release(); } | |
223 | ||
224 | // Smart pointer functions | |
225 | T& operator*() const { return *this->m_pobj; } | |
226 | T* operator->() const { return this->m_pobj; } | |
227 | ||
228 | T* get() const { return this->m_pobj; } | |
229 | operator T*() const { return get(); } | |
230 | }; | |
231 | ||
232 | ||
233 | // Weak ref implementation assign objects are queried for wxTrackable | |
234 | // using dynamic_cast<> | |
235 | template <class T> | |
236 | class wxWeakRefDynamic : public wxTrackerNode | |
237 | { | |
238 | public: | |
239 | wxWeakRefDynamic() : m_pobj(NULL) { } | |
240 | ||
241 | wxWeakRefDynamic(T* pobj) : m_pobj(pobj) | |
242 | { | |
243 | Assign(pobj); | |
244 | } | |
245 | ||
246 | virtual ~wxWeakRefDynamic() { Release(); } | |
247 | ||
248 | // Smart pointer functions | |
249 | T& operator * (){ wxASSERT(this->m_pobj); return *m_pobj; } | |
250 | T* operator -> (){ wxASSERT(this->m_pobj); return m_pobj; } | |
251 | T* operator = (T* pobj) { Assign(pobj); return m_pobj; } | |
252 | ||
253 | T* get(){ return this->m_pobj; } | |
254 | ||
255 | // operator T* (){ return this->m_pobj; } | |
256 | ||
257 | // test for pointer validity: defining conversion to unspecified_bool_type | |
258 | // and not more obvious bool to avoid implicit conversions to integer types | |
259 | typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const; | |
260 | operator unspecified_bool_type() const | |
261 | { | |
262 | return m_pobj ? &wxWeakRef<T>::get : NULL; | |
263 | } | |
264 | ||
265 | // Assign from another weak ref, point to same object | |
266 | T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; } | |
267 | ||
268 | void Release() | |
269 | { | |
270 | // Release old object if any | |
271 | if( m_pobj ) | |
272 | { | |
273 | // Remove ourselves from object tracker list | |
274 | wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj); | |
275 | wxASSERT(pt); | |
276 | pt->RemoveNode(this); | |
277 | m_pobj = NULL; | |
278 | } | |
279 | } | |
280 | ||
281 | protected: | |
282 | void Assign(T *pobj) | |
283 | { | |
284 | if ( m_pobj == pobj ) | |
285 | return; | |
286 | ||
287 | Release(); | |
288 | ||
289 | // Now set new trackable object | |
290 | if ( pobj ) | |
291 | { | |
292 | // Add ourselves to object tracker list | |
293 | wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj); | |
294 | if ( pt ) | |
295 | { | |
296 | pt->AddNode(this); | |
297 | m_pobj = pobj; | |
298 | } | |
299 | else | |
300 | { | |
301 | // If the object we want to track does not support wxTackable, then | |
302 | // log a message and keep the NULL object pointer. | |
303 | wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); | |
304 | } | |
305 | } | |
306 | } | |
307 | ||
308 | virtual void OnObjectDestroy() | |
309 | { | |
310 | wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" ); | |
311 | ||
312 | m_pobj = NULL; | |
313 | } | |
314 | ||
315 | T *m_pobj; | |
316 | }; | |
317 | ||
318 | // Provide some basic types of weak references | |
319 | class WXDLLIMPEXP_FWD_BASE wxEvtHandler; | |
320 | class WXDLLIMPEXP_FWD_CORE wxWindow; | |
321 | ||
322 | typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef; | |
323 | typedef wxWeakRef<wxWindow> wxWindowRef; | |
324 | ||
325 | #endif // _WX_WEAKREF_H_ | |
326 |