X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/9dd5ff5baafda3cd6c427047b92886933bdec6a5..9c34a216817028bc533e07873d047208a96b05a2:/include/wx/weakref.h diff --git a/include/wx/weakref.h b/include/wx/weakref.h index a893ba4049..e612db81b2 100644 --- a/include/wx/weakref.h +++ b/include/wx/weakref.h @@ -2,7 +2,7 @@ // Name: wx/weakref.h // Purpose: wxWeakRef - Generic weak references for wxWidgets // Author: Arne Steinarson -// Created: 2007-12-27 +// Created: 27 Dec 07 // RCS-ID: $Id$ // Copyright: (c) 2007 Arne Steinarson // Licence: wxWindows licence @@ -11,93 +11,326 @@ #ifndef _WX_WEAKREF_H_ #define _WX_WEAKREF_H_ -#include +#include "wx/tracker.h" -// A weak reference to an object of type T, where T has type wxTrackable -// as one of its base classes (in a static or dynamic sense). -template -class wxWeakRef : public wxTrackerNode + +// 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 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: - typedef T element_type; - - wxWeakRef(T *pobj = NULL) : m_pobj(NULL) { Assign(pobj); } - - virtual ~wxWeakRef() { Assign(NULL); } - - T * get() const - { - return m_pobj; - } - - T* operator->() - { - wxASSERT(m_pobj != NULL); - return m_pobj; - } - - T& operator*() const - { - wxASSERT(m_pobj != NULL); - return *m_pobj; - } - - T* operator=(T *pobj) + wxWeakRefStatic() : m_pobj(NULL) { } + + void Release() { - Assign(pobj); - return m_pobj; + // 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; + } } - // Assign from another weak ref, point to same object - T* operator = (const wxWeakRef &wr) - { - Assign(wr); - return m_pobj; - } - virtual void OnObjectDestroy() { // Tracked object itself removes us from list of trackers - wxASSERT( m_pobj ); + wxASSERT(m_pobj != NULL); m_pobj = NULL; } protected: - friend class wxTrackableBase; - friend class wxEvtHandler; - - virtual wxTrackerNodeType GetType() { return WeakRef; } - void Assign(T* pobj) { if ( m_pobj == pobj ) return; - // First release old object if any + 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 - // This does static_cast if available, otherwise it tries dynamic cast - wxTrackableBase *pt = wxTrackableCaster::value >::Cast(m_pobj); + 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 ); + } + +#ifndef wxNO_RTTI + 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 // RTTI enabled + + 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: + typedef T element_type; + + // Default ctor + wxWeakRef() { } + + // Enabling this ctor for VC6 results in mysterious compilation failures in + // wx/window.h when assigning wxWindow pointers (FIXME-VC6) +#ifndef __VISUALC6__ + // Ctor from the object of this type: this is needed as the template ctor + // below is not used by at least g++4 when a literal NULL is used + wxWeakRef(T *pobj) + { + this->Assign(pobj); + } +#endif // !__VISUALC6__ + + // When we have the full type here, static_cast<> will always work + // (or give a straight compiler error). + template + wxWeakRef(TDerived* pobj) + { + this->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) + { + this->Assign(wr.get()); + } + + wxWeakRef& operator=(const wxWeakRef& wr) + { + this->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; } +}; + + +#ifndef wxNO_RTTI + +// 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 ) { - wxTrackableBase *pt = wxTrackableCaster::value >::Cast(pobj); - if( pt ) + // Add ourselves to object tracker list + wxTrackable *pt = dynamic_cast(pobj); + if ( pt ) { - pt->AddNode( this ); + pt->AddNode(this); m_pobj = pobj; } else { - // If the tracked we want to track does not support wxTackableBase, then - // log a message and keep the NULL object pointer. - wxLogWarning( _T("wxWeakRef::Assign - Type does not provide wxTrackableBase - resetting tracked object") ); + // 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" ); } } } @@ -105,12 +338,14 @@ protected: T *m_pobj; }; +#endif // RTTI enabled + + // Provide some basic types of weak references -class WXDLLIMPEXP_FWD_BASE wxObject; class WXDLLIMPEXP_FWD_BASE wxEvtHandler; class WXDLLIMPEXP_FWD_CORE wxWindow; -typedef wxWeakRef wxObjectRef; + typedef wxWeakRef wxEvtHandlerRef; typedef wxWeakRef wxWindowRef;