///////////////////////////////////////////////////////////////////////////// // Name: wx/weakref.h // Purpose: wxWeakRef - Generic weak references for wxWidgets // Author: Arne Steinarson // Created: 27 Dec 07 // RCS-ID: $Id$ // Copyright: (c) 2007 Arne Steinarson // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// #ifndef _WX_WEAKREF_H_ #define _WX_WEAKREF_H_ #include "wx/tracker.h" // Some compilers (VC6, Borland, g++ < 3.3) have problem with template specialization. // However, this is only used for optimization purposes (a smaller wxWeakRef pointer) // (and the corner case of wxWeakRef). So for those compilers, we can fall // back to the non-optimal case, where we use a the same type of weak ref (static one) // in all cases. See defs.h for various setting these defines depending on compiler. #if !defined(HAVE_PARTIAL_SPECIALIZATION) || \ !defined(HAVE_TEMPLATE_OVERLOAD_RESOLUTION) || \ (defined(__GNUC__) && !wxCHECK_GCC_VERSION(3, 3)) #define USE_ONLY_STATIC_WEAKREF #endif #ifndef USE_ONLY_STATIC_WEAKREF // Avoid including this for simpler compilers #include "wx/meta/convertible.h" #include "wx/meta/int2type.h" template struct wxIsStaticTrackable { enum { value = wxConvertibleTo::value }; }; #endif // !USE_ONLY_STATIC_WEAKREF // Weak ref implementation when T has wxTrackable as a known base class template class wxWeakRefStatic : public wxTrackerNode { public: wxWeakRefStatic() : m_pobj(NULL) { } void Release() { // Release old object if any if ( m_pobj ) { // Remove ourselves from object tracker list wxTrackable *pt = static_cast(m_pobj); pt->RemoveNode(this); m_pobj = NULL; } } virtual void OnObjectDestroy() { // Tracked object itself removes us from list of trackers wxASSERT(m_pobj != NULL); m_pobj = NULL; } protected: void Assign(T* pobj) { if ( m_pobj == pobj ) return; Release(); // Now set new trackable object if ( pobj ) { // Add ourselves to object tracker list wxTrackable *pt = static_cast(pobj); pt->AddNode(this); m_pobj = pobj; } } void AssignCopy(const wxWeakRefStatic& wr) { Assign( wr.m_pobj ); } T *m_pobj; }; #ifndef USE_ONLY_STATIC_WEAKREF template struct wxWeakRefImpl; // Intermediate class, to select the static case above. template struct wxWeakRefImpl : public wxWeakRefStatic { enum { value = 1 }; }; // Weak ref implementation when T does not have wxTrackable as known base class template struct wxWeakRefImpl : public wxTrackerNode { void Release() { // Release old object if any if ( m_pobj ) { // Remove ourselves from object tracker list m_ptbase->RemoveNode(this); m_pobj = NULL; m_ptbase = NULL; } } virtual void OnObjectDestroy() { // Tracked object itself removes us from list of trackers wxASSERT(m_pobj != NULL); m_pobj = NULL; m_ptbase = NULL; } protected: wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { } // Assign receives most derived class here and can use that template void Assign( TDerived* pobj ) { AssignHelper( pobj, wxInt2Type::value>() ); } template void AssignHelper(TDerived* pobj, wxInt2Type) { wxTrackable *ptbase = static_cast(pobj); DoAssign( pobj, ptbase ); } #ifdef HAVE_DYNAMIC_CAST void AssignHelper(T* pobj, wxInt2Type) { // A last way to get a trackable pointer wxTrackable *ptbase = dynamic_cast(pobj); if ( ptbase ) { DoAssign( pobj, ptbase ); } else { wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); Release(); } } #endif // HAVE_DYNAMIC_CAST void AssignCopy(const wxWeakRefImpl& wr) { DoAssign(wr.m_pobj, wr.m_ptbase); } void DoAssign( T* pobj, wxTrackable *ptbase ) { if( m_pobj==pobj ) return; Release(); // Now set new trackable object if( pobj ) { // Add ourselves to object tracker list wxASSERT( ptbase ); ptbase->AddNode( this ); m_pobj = pobj; m_ptbase = ptbase; } } T *m_pobj; wxTrackable *m_ptbase; }; #endif // #ifndef USE_ONLY_STATIC_WEAKREF // A weak reference to an object of type T, where T has base wxTrackable // (usually statically but if not dynamic_cast<> is tried). template class wxWeakRef : public #ifdef USE_ONLY_STATIC_WEAKREF wxWeakRefStatic #else wxWeakRefImpl::value != 0> #endif { public: // Default ctor wxWeakRef() { } // When we have the full type here, static_cast<> will always work // (or give a straight compiler error). template wxWeakRef(TDerived* pobj) { Assign(pobj); } // We need this copy ctor, since otherwise a default compiler (binary) copy // happens (if embedded as an object member). wxWeakRef(const wxWeakRef& wr) { Assign(wr.get()); } template wxWeakRef& operator=(TDerived* pobj) { this->Assign(pobj); return *this; } wxWeakRef& operator=(const wxWeakRef& wr) { AssignCopy(wr); return *this; } virtual ~wxWeakRef() { this->Release(); } // Smart pointer functions T& operator*() const { return *this->m_pobj; } T* operator->() const { return this->m_pobj; } T* get() const { return this->m_pobj; } operator T*() const { return this->m_pobj; } }; #ifdef HAVE_DYNAMIC_CAST // Weak ref implementation assign objects are queried for wxTrackable // using dynamic_cast<> template class wxWeakRefDynamic : public wxTrackerNode { public: wxWeakRefDynamic() : m_pobj(NULL) { } wxWeakRefDynamic(T* pobj) : m_pobj(pobj) { Assign(pobj); } wxWeakRefDynamic(const wxWeakRef& wr) { Assign(wr.get()); } virtual ~wxWeakRefDynamic() { Release(); } // Smart pointer functions T& operator*() const { wxASSERT(m_pobj); return *m_pobj; } T* operator->() const { wxASSERT(m_pobj); return m_pobj; } T* get() const { return m_pobj; } operator T* () const { return m_pobj; } T* operator = (T* pobj) { Assign(pobj); return m_pobj; } // Assign from another weak ref, point to same object T* operator = (const wxWeakRef &wr) { Assign( wr.get() ); return m_pobj; } void Release() { // Release old object if any if( m_pobj ) { // Remove ourselves from object tracker list wxTrackable *pt = dynamic_cast(m_pobj); wxASSERT(pt); pt->RemoveNode(this); m_pobj = NULL; } } virtual void OnObjectDestroy() { wxASSERT_MSG(m_pobj, "tracked object should have removed us itself"); m_pobj = NULL; } protected: void Assign(T *pobj) { if ( m_pobj == pobj ) return; Release(); // Now set new trackable object if ( pobj ) { // Add ourselves to object tracker list wxTrackable *pt = dynamic_cast(pobj); if ( pt ) { pt->AddNode(this); m_pobj = pobj; } else { // If the object we want to track does not support wxTackable, then // log a message and keep the NULL object pointer. wxFAIL_MSG( "Tracked class should inherit from wxTrackable" ); } } } T *m_pobj; }; #endif // #ifdef HAVE_DYNAMIC_CAST // Provide some basic types of weak references class WXDLLIMPEXP_FWD_BASE wxEvtHandler; class WXDLLIMPEXP_FWD_CORE wxWindow; typedef wxWeakRef wxEvtHandlerRef; typedef wxWeakRef wxWindowRef; #endif // _WX_WEAKREF_H_