improvements to wxWeakRef and related classes

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@51187 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-01-13 01:12:13 +00:00
parent 0fb0ecc452
commit cc6ceca789
12 changed files with 983 additions and 309 deletions

View File

@@ -467,6 +467,7 @@
\input windowdc.tex \input windowdc.tex
\input destroyevt.tex \input destroyevt.tex
\input weakref.tex \input weakref.tex
\input weakrefdynamic.tex
\input wnddisbl.tex \input wnddisbl.tex
\input wizard.tex \input wizard.tex
\input wizevt.tex \input wizevt.tex

View File

@@ -1,5 +1,4 @@
\section{\class{wxTrackable}}\label{wxtrackable}
\section{\class{wxTrackableBase}}\label{wxtrackablebase}
Add-on base class for a trackable object. This class maintains Add-on base class for a trackable object. This class maintains
an internal linked list of classes of type wxTrackerNode and an internal linked list of classes of type wxTrackerNode and
@@ -10,7 +9,7 @@ API. Its only use is by deriving another class from it to
make it trackable. make it trackable.
\begin{verbatim} \begin{verbatim}
class MyClass: public Foo, public TrackableBase class MyClass: public Foo, public wxTrackable
{ {
// whatever // whatever
} }
@@ -31,18 +30,7 @@ No base class
\section{\class{wxTrackable}}\label{wxtrackable} \section{\class{wxTrackable}}\label{wxtrackable}
The only difference to \helpref{wxTrackableBase}{wxtrackablebase} is
that this class adds a virtual table to enable dynamic\_cast query for
wxTrackable.
\wxheading{Derived from}
\helpref{wxTrackableBase}{wxtrackablebase}
\wxheading{Include files} \wxheading{Include files}
<tracker.h> <tracker.h>
\wxheading{Data structures}

View File

@@ -6,11 +6,11 @@ such as \helpref{wxEvtHandler}{wxevthandler}, \helpref{wxWindow}{wxwindow} and
pointer, but when the object pointed is destroyed, the weak reference is pointer, but when the object pointed is destroyed, the weak reference is
automatically reset to a NULL pointer. automatically reset to a NULL pointer.
wxWeakref<T> can be used whenever one must keep a pointer to an object wxWeakRef<T> can be used whenever one must keep a pointer to an object
that does not directly own, and that may be destroyed before the object that one does not directly own, and that may be destroyed before the object
holding the reference. holding the reference.
wxWeakref<T> is a small object and the mechanism behind it is fast wxWeakRef<T> is a small object and the mechanism behind it is fast
(\textbf{O(1)}). So the overall cost of using it is small. (\textbf{O(1)}). So the overall cost of using it is small.
@@ -31,9 +31,8 @@ wxWeakref<T> is a small object and the mechanism behind it is fast
wxASSERT( wr==NULL ); wxASSERT( wr==NULL );
\end{verbatim} \end{verbatim}
wxWeakref<T> works for any objects that are derived from wxWeakRef<T> works for any objects that are derived from \helpref{wxTrackable}{wxtrackable}.
\helpref{wxTrackableBase}{wxtrackablebase} or \helpref{wxTrackable}{wxtrackable}. By default, wxEvtHandler and wxWindow derive from wxTrackable. However,
By default, wxEvtHandler and wxWindow derive from wxTrackableBase. However,
wxObject does not, so types like \helpref{wxFont}{wxfont} and wxObject does not, so types like \helpref{wxFont}{wxfont} and
\helpref{wxColour}{wxcolour} are not trackable. The example below shows how to \helpref{wxColour}{wxcolour} are not trackable. The example below shows how to
create a wxObject derived class that is trackable: create a wxObject derived class that is trackable:
@@ -44,18 +43,11 @@ create a wxObject derived class that is trackable:
}; };
\end{verbatim} \end{verbatim}
\textbf{Note:} Custom trackable objects should derive from wxTrackable
if one wants to reference them from a \texttt{wxWeakRef<wxObject>}. The
difference between the two base classes is that wxTrackableBase
has no virtual member functions (no VTable), and thus cannot be detected
through \texttt{dynamic\_cast<>}.
\wxheading{Predefined types} \wxheading{Predefined types}
The following types of weak references are predefined: The following types of weak references are predefined:
\begin{verbatim} \begin{verbatim}
typedef wxWeakRef<wxObject> wxObjectRef;
typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef; typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef;
typedef wxWeakRef<wxWindow> wxWindowRef; typedef wxWeakRef<wxWindow> wxWindowRef;
\end{verbatim} \end{verbatim}
@@ -134,7 +126,7 @@ method will cause an assert in debug mode.
\membersection{wxWeakRef<T>::operator=}\label{wxweakrefoperatorassign} \membersection{wxWeakRef<T>::operator=}\label{wxweakrefoperatorassign}
\func{T* operator}{operator=}{\param{T* }{pobj}} \func{T*}{operator=}{\param{T* }{pobj}}
Releases the currently tracked object and starts tracking {\it pobj}. Releases the currently tracked object and starts tracking {\it pobj}.
A weak reference may be reset by passing {\it NULL} as {\it pobj}. A weak reference may be reset by passing {\it NULL} as {\it pobj}.
@@ -142,12 +134,19 @@ A weak reference may be reset by passing {\it NULL} as {\it pobj}.
\membersection{wxWeakRef<T>::operator =}\label{wxweakrefoperatorassign2} \membersection{wxWeakRef<T>::operator =}\label{wxweakrefoperatorassign2}
\func{T* operator}{operator =}{\param{wxWeakRef<T>\& }{wr}} \func{T*}{operator =}{\param{wxWeakRef<T>\& }{wr}}
Release currently tracked object and start tracking the same object as Release currently tracked object and start tracking the same object as
the wxWeakRef {\it wr}. the wxWeakRef {\it wr}.
\membersection{wxWeakRef<T>::Release}\label{wxweakrefrelease}
\func{void}{Release}{\void}
Release currently tracked object and rests object reference.
\membersection{wxWeakRef<T>::OnObjectDestroy}\label{wxweakrefonobjectdestroy} \membersection{wxWeakRef<T>::OnObjectDestroy}\label{wxweakrefonobjectdestroy}
\func{virtual void}{OnObjectDestroy}{\void} \func{virtual void}{OnObjectDestroy}{\void}

View File

@@ -0,0 +1,20 @@
\section{\class{wxWeakRefDynamic<T>}}\label{wxweakrefdynamic}
wxWeakRefDynamic<T> is a template class for weak references that is used in
the same way as wxWeakRef<T>. The only difference is that wxWeakRefDynamic
defaults to using \texttt{dynamic\_cast<>} for establishing the object
reference (while wxWeakRef defaults to \texttt{static\_cast<>}).
So, wxWeakRef will detect a type mismatch during compile time and will
have a little better run-time performance. The role of wxWeakRefDynamic
is to handle objects which derived type one does not know.
\textbf{Note:} wxWeakRef<T> selects an implementation based on the static type
of T. If T does not have wxTrackable statically, it defaults to to a mixed-
mode operation, where it uses \texttt{dynamic\_cast<>} as the last measure (if
available from the compiler and enabled when building wxWidgets).
For general cases, wxWeakRef<T> is the better choice.
For API documentation, see: \helpref{wxWeakRef}{wxweakref}

View File

@@ -444,6 +444,21 @@ typedef short int WXTYPE;
#endif #endif
#endif /* HAVE_WOSTREAM */ #endif /* HAVE_WOSTREAM */
// ----------------------------------------------------------------------------
// other C++ features
// ----------------------------------------------------------------------------
#ifndef HAVE_PARTIAL_SPECIALIZATION
// be optimistic by default
#define HAVE_PARTIAL_SPECIALIZATION
#endif
#ifdef __VISUALC__
#if __VISUALC__ < 1310
#undef HAVE_PARTIAL_SPECIALIZATION
#endif
#endif // __VISUALC__
/* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */
/* portable calling conventions macros */ /* portable calling conventions macros */
/* ---------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------------- */

View File

@@ -39,6 +39,7 @@ class WXDLLIMPEXP_FWD_BASE wxList;
#endif // wxUSE_GUI #endif // wxUSE_GUI
class WXDLLIMPEXP_FWD_BASE wxEvtHandler; class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
class wxEventConnectionRef;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Event types // Event types
@@ -2258,44 +2259,11 @@ protected:
DECLARE_NO_COPY_CLASS(wxEventHashTable) DECLARE_NO_COPY_CLASS(wxEventHashTable)
}; };
// ----------------------------------------------------------------------------
// wxEventConnectionRef: A class that represents all connections between two event
// handlers and enables automatic disconnect when an event handler sink goes
// out of scope. Each connection/disconnect increases/decreases ref count, and
// when zero the node goes out of scope.
// ----------------------------------------------------------------------------
struct wxEventConnectionRef : public wxTrackerNode {
wxEventConnectionRef() : m_src(0), m_sink(0), m_refCount(0) { }
wxEventConnectionRef( wxEvtHandler *src, wxEvtHandler *sink );
virtual ~wxEventConnectionRef();
// The sink is being destroyed
virtual void OnObjectDestroy( );
virtual wxTrackerNodeType GetType( ){ return EventConnectionRef; }
void IncRef( ) { m_refCount++; }
void DecRef( );
protected:
wxEvtHandler *m_src, *m_sink;
int m_refCount;
friend class wxEvtHandler;
private:
// It makes no sense to copy objects of this class
wxEventConnectionRef& operator = (const wxEventConnectionRef& WXUNUSED(other)) { wxFAIL; return *this; }
};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxEvtHandler: the base class for all objects handling wxWidgets events // wxEvtHandler: the base class for all objects handling wxWidgets events
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackableBase class WXDLLIMPEXP_BASE wxEvtHandler : public wxObject, public wxTrackable
{ {
public: public:
wxEvtHandler(); wxEvtHandler();
@@ -2463,12 +2431,61 @@ protected:
virtual void *DoGetClientData() const; virtual void *DoGetClientData() const;
// Search tracker objects for event connection with this sink // Search tracker objects for event connection with this sink
wxEventConnectionRef *FindRefInTrackerList( wxEvtHandler *eventSink ); wxEventConnectionRef *FindRefInTrackerList(wxEvtHandler *eventSink);
private: private:
DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler) DECLARE_DYNAMIC_CLASS_NO_COPY(wxEvtHandler)
}; };
// ----------------------------------------------------------------------------
// wxEventConnectionRef represents all connections between two event handlers
// and enables automatic disconnect when an event handler sink goes out of
// scope. Each connection/disconnect increases/decreases ref count, and
// when it reaches zero the node goes out of scope.
// ----------------------------------------------------------------------------
class wxEventConnectionRef : public wxTrackerNode
{
public:
wxEventConnectionRef() : m_src(NULL), m_sink(NULL), m_refCount(0) { }
wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
: m_src(src), m_sink(sink), m_refCount(1)
{
m_sink->AddNode(this);
}
// The sink is being destroyed
virtual void OnObjectDestroy( )
{
if ( m_src )
m_src->OnSinkDestroyed( m_sink );
delete this;
}
virtual wxEventConnectionRef *ToEventConnection() { return this; }
void IncRef() { m_refCount++; }
void DecRef()
{
if ( !--m_refCount )
{
// The sink holds the only external pointer to this object
if ( m_sink )
m_sink->RemoveNode(this);
delete this;
}
}
private:
wxEvtHandler *m_src,
*m_sink;
int m_refCount;
friend class wxEvtHandler;
DECLARE_NO_ASSIGN_CLASS(wxEventConnectionRef)
};
// Post a message to the given eventhandler which will be processed during the // Post a message to the given eventhandler which will be processed during the
// next event loop iteration // next event loop iteration
inline void wxPostEvent(wxEvtHandler *dest, const wxEvent& event) inline void wxPostEvent(wxEvtHandler *dest, const wxEvent& event)

View File

@@ -2,7 +2,7 @@
// Name: wx/tracker.h // Name: wx/tracker.h
// Purpose: Support class for object lifetime tracking (wxWeakRef<T>) // Purpose: Support class for object lifetime tracking (wxWeakRef<T>)
// Author: Arne Steinarson // Author: Arne Steinarson
// Created: 2007-12-28 // Created: 28 Dec 07
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson // Copyright: (c) 2007 Arne Steinarson
// Licence: wxWindows licence // Licence: wxWindows licence
@@ -11,133 +11,73 @@
#ifndef _WX_TRACKER_H_ #ifndef _WX_TRACKER_H_
#define _WX_TRACKER_H_ #define _WX_TRACKER_H_
#include "wx/defs.h"
// This structure represents an object tracker and is stored in a linked list class wxEventConnectionRef;
// This class represents an object tracker and is stored in a linked list
// in the tracked object. It is only used in one of its derived forms. // in the tracked object. It is only used in one of its derived forms.
struct wxTrackerNode { class WXDLLIMPEXP_BASE wxTrackerNode
wxTrackerNode( ) : m_nxt(0) { } {
public:
wxTrackerNode() : m_nxt(NULL) { }
virtual ~wxTrackerNode() { } virtual ~wxTrackerNode() { }
virtual void OnObjectDestroy( ) = 0;
// This is to tell the difference between different tracker node types.
// It's a replacement of dynamic_cast<> for this class since dynamic_cast
// may be disabled (and we don't have wxDynamicCast since wxTrackerNode
// is not derived wxObject).
enum wxTrackerNodeType { WeakRef, EventConnectionRef };
virtual wxTrackerNodeType GetType() = 0; virtual void OnObjectDestroy() = 0;
protected: virtual wxEventConnectionRef *ToEventConnection() { return NULL; }
private:
wxTrackerNode *m_nxt; wxTrackerNode *m_nxt;
friend class wxTrackableBase; // For list access
friend class wxTrackable; // For list access
friend class wxEvtHandler; // For list access friend class wxEvtHandler; // For list access
}; };
// Add-on base class for a trackable object. // Add-on base class for a trackable object.
struct wxTrackableBase { class wxTrackable
wxTrackableBase() : m_first(0) { } {
~wxTrackableBase() public:
{ wxTrackable() : m_first(NULL) { }
~wxTrackable()
{
// Notify all registered refs // Notify all registered refs
while ( m_first )
wxTrackerNode *first;
while( m_first )
{ {
first = m_first; wxTrackerNode * const first = m_first;
first->OnObjectDestroy( ); m_first = first->m_nxt;
RemoveNode(first); first->OnObjectDestroy();
} }
} }
void AddNode( wxTrackerNode *prn ) void AddNode(wxTrackerNode *prn)
{ {
prn->m_nxt = m_first; prn->m_nxt = m_first;
m_first = prn; m_first = prn;
} }
void RemoveNode( wxTrackerNode *prn )
void RemoveNode(wxTrackerNode *prn)
{ {
for( wxTrackerNode **pprn=&m_first; *pprn; pprn=&(*pprn)->m_nxt ) for ( wxTrackerNode **pprn = &m_first; *pprn; pprn = &(*pprn)->m_nxt )
{ {
if( *pprn==prn ) if ( *pprn == prn )
{ {
*pprn = prn->m_nxt; *pprn = prn->m_nxt;
return; return;
} }
} }
// Not found, an error.
wxASSERT( false ); wxFAIL_MSG( "removing invalid tracker node" );
} }
wxTrackerNode* GetFirst( ){ return m_first; }
// If trying to copy this object, then do not copy its ref list. wxTrackerNode *GetFirst() const { return m_first; }
wxTrackableBase& operator = (const wxTrackableBase& WXUNUSED(other)) { return *this; }
protected:
protected:
wxTrackerNode *m_first; wxTrackerNode *m_first;
DECLARE_NO_COPY_CLASS(wxTrackable)
}; };
// The difference to wxTrackableBase is that this class adds
// a VTable to enable dynamic_cast query for wxTrackable.
struct wxTrackable : public wxTrackableBase
{
virtual ~wxTrackable(){ }
};
// Helper to decide if an object has a base class or not
// (strictly speaking, this test succeeds if a type is convertible
// to another type in some way.)
template<class T, class B>
struct wxHasBase{
static char Match( B* pb );
static int Match( ... );
enum { value = (sizeof(Match((T*)NULL))==sizeof(char)) };
};
// VC++ before 7.1 does not have partial template specialization
#ifdef __VISUALC__
#if __VISUALC__ < 1310
#define HAVE_NO_PARTIAL_SPECIALIZATION
#endif
#endif
#if defined(HAVE_DYNAMIC_CAST) && !defined(HAVE_NO_PARTIAL_SPECIALIZATION)
// A structure to cast to wxTrackableBase, using either static_cast<> or dynamic_cast<>.
template<class T,bool is_static>
struct wxTrackableCaster;
template <class T>
struct wxTrackableCaster<T,true> {
static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
};
template <class T>
struct wxTrackableCaster<T,false> {
static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
};
#else
#if defined(HAVE_DYNAMIC_CAST)
// If we have dynamic_cast, default to that. For gcc, dynamic_cast<> does the job
// of both the dynamic and the static case. It could be that all compilers do it
// that way, rendering the specialization code above rednundant.
template <class T,bool is_static>
struct wxTrackableCaster {
static wxTrackableBase* Cast(T* pt){ return dynamic_cast<wxTrackableBase*>(pt); }
};
#else
// No dynamic_cast<> is available.
// We use static_cast<>, that gives support for wxEvtHandler and wxWindow references.
// We don't get weak refs to other wxObject derived types.
template <class T,bool is_static>
struct wxTrackableCaster {
static wxTrackableBase* Cast(T* pt){ return static_cast<wxTrackableBase*>(pt); }
};
#endif
#endif
#endif // _WX_TRACKER_H_ #endif // _WX_TRACKER_H_

View File

@@ -2,7 +2,7 @@
// Name: wx/weakref.h // Name: wx/weakref.h
// Purpose: wxWeakRef - Generic weak references for wxWidgets // Purpose: wxWeakRef - Generic weak references for wxWidgets
// Author: Arne Steinarson // Author: Arne Steinarson
// Created: 2007-12-27 // Created: 27 Dec 07
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson // Copyright: (c) 2007 Arne Steinarson
// Licence: wxWindows licence // Licence: wxWindows licence
@@ -11,19 +11,243 @@
#ifndef _WX_WEAKREF_H_ #ifndef _WX_WEAKREF_H_
#define _WX_WEAKREF_H_ #define _WX_WEAKREF_H_
#include <wx/tracker.h> #include "wx/tracker.h"
// A weak reference to an object of type T, where T has type wxTrackable #include "wx/meta/convertible.h"
// as one of its base classes (in a static or dynamic sense). #include "wx/meta/int2type.h"
template<class T>
class wxWeakRef : public wxTrackerNode template <class T>
struct wxIsStaticTrackable
{
enum { value = wxConvertibleTo<T, wxTrackable>::value };
};
// Weak ref implementation when T has wxTrackable as a known base class
template <class T>
class wxWeakRefStatic : public wxTrackerNode
{ {
public: public:
typedef T element_type; wxWeakRefStatic() : m_pobj(NULL) { }
wxWeakRef(T *pobj = NULL) : m_pobj(NULL) { Assign(pobj); }
virtual ~wxWeakRef() { Assign(NULL); } void Release()
{
// Release old object if any
if ( m_pobj )
{
// Remove ourselves from object tracker list
wxTrackable *pt = static_cast<wxTrackable*>(m_pobj);
pt->RemoveNode(this);
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<wxTrackable*>(pobj);
pt->AddNode(this);
m_pobj = pobj;
}
}
void AssignCopy( const wxWeakRefStatic& wr )
{
Assign( wr.m_pobj );
}
virtual void OnObjectDestroy()
{
// Tracked object itself removes us from list of trackers
wxASSERT( m_pobj!=NULL );
m_pobj = NULL;
}
T *m_pobj;
};
#ifdef HAVE_PARTIAL_SPECIALIZATION
template<class T,bool use_static>
struct wxWeakRefImpl;
// Intermediate class, to select the static case above.
template <class T>
struct wxWeakRefImpl<T, true> : public wxWeakRefStatic<T>
{
enum { value = 1 };
};
// Weak ref implementation when T does not have wxTrackable as known base class
template<class T>
struct wxWeakRefImpl<T, false> : 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;
}
}
protected:
wxWeakRefImpl() : m_pobj(NULL), m_ptbase(NULL) { }
// Assign receives most derived class here and can use that
template <class TDerived>
void Assign( TDerived* pobj )
{
AssignHelper( pobj, wxInt2Type<wxIsStaticTrackable<TDerived>::value>() );
}
template <class TDerived>
void AssignHelper(TDerived* pobj, wxInt2Type<true>)
{
wxTrackable *ptbase = static_cast<wxTrackable*>(pobj);
DoAssign( pobj, ptbase );
}
#ifdef HAVE_DYNAMIC_CAST
void AssignHelper(T* pobj, wxInt2Type<false>)
{
// A last way to get a trackable pointer
wxTrackable *ptbase = dynamic_cast<wxTrackable*>(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;
}
}
virtual void OnObjectDestroy()
{
// Tracked object itself removes us from list of trackers
wxASSERT( m_pobj!=NULL );
m_pobj = NULL;
m_ptbase = NULL;
}
T *m_pobj;
wxTrackable *m_ptbase;
};
#endif // HAVE_PARTIAL_SPECIALIZATION
// A weak reference to an object of type T, where T has type wxTrackable
// (usually statically but if not dynamic_cast<> is tried).
template <class T>
class wxWeakRef : public
#ifdef HAVE_PARTIAL_SPECIALIZATION
wxWeakRefImpl<T, wxIsStaticTrackable<T>::value>
#else
wxWeakRefStatic<T>
#endif
{
public:
// Default ctor
wxWeakRef() { }
// When we have the full type here, static_cast<> will always work
// (or give a straight compiler error).
template <class TDerived>
wxWeakRef(TDerived* pobj)
{
Assign(pobj);
}
template <class TDerived>
wxWeakRef<T>& operator=(TDerived* pobj)
{
Assign(pobj);
return *this;
}
wxWeakRef<T>& operator=(const wxWeakRef<T>& wr)
{
AssignCopy(wr);
return *this;
}
virtual ~wxWeakRef() { Release(); }
// Smart pointer functions
T& operator*() const { return *m_pobj; }
T* operator->() const { return m_pobj; }
T* get() const { return m_pobj; }
// test for pointer validity: defining conversion to unspecified_bool_type
// and not more obvious bool to avoid implicit conversions to integer types
typedef T *(wxWeakRef<T>::*unspecified_bool_type)() const;
operator unspecified_bool_type() const
{
return this->m_pobj ? &wxWeakRef<T>::get : NULL;
}
};
// Weak ref implementation assign objects are queried for wxTrackable
// using dynamic_cast<>
template<class T>
class wxWeakRefDynamic : public wxTrackerNode
{
public:
wxWeakRefDynamic() : m_pobj(NULL) { }
wxWeakRefDynamic(T* pobj) : m_pobj(pobj)
{
Assign(pobj);
}
virtual ~wxWeakRefDynamic() { Release(); }
// Smart pointer functions
T& operator * (){ wxASSERT(this->m_pobj); return *m_pobj; }
T* operator -> (){ wxASSERT(this->m_pobj); return m_pobj; }
T* operator = (T* pobj) { Assign(pobj); return m_pobj; }
T* get(){ return this->m_pobj; }
// operator T* (){ return this->m_pobj; }
// test for pointer validity: defining conversion to unspecified_bool_type // test for pointer validity: defining conversion to unspecified_bool_type
// and not more obvious bool to avoid implicit conversions to integer types // and not more obvious bool to avoid implicit conversions to integer types
@@ -33,92 +257,68 @@ public:
return m_pobj ? &wxWeakRef<T>::get : NULL; return m_pobj ? &wxWeakRef<T>::get : 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)
{
Assign(pobj);
return m_pobj;
}
// Assign from another weak ref, point to same object // Assign from another weak ref, point to same object
T* operator = (const wxWeakRef<T> &wr) T* operator = (const wxWeakRef<T> &wr) { Assign( wr.get() ); return this->m_pobj; }
{
Assign(wr); void Release()
return m_pobj;
}
virtual void OnObjectDestroy()
{ {
// Tracked object itself removes us from list of trackers // Release old object if any
wxASSERT( m_pobj ); if( m_pobj )
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
if ( m_pobj )
{ {
// Remove ourselves from object tracker list // Remove ourselves from object tracker list
// This does static_cast if available, otherwise it tries dynamic cast wxTrackable *pt = dynamic_cast<wxTrackable*>(m_pobj);
wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(m_pobj);
wxASSERT(pt); wxASSERT(pt);
pt->RemoveNode(this); pt->RemoveNode(this);
m_pobj = NULL; m_pobj = NULL;
} }
}
protected:
void Assign(T *pobj)
{
if ( m_pobj == pobj )
return;
Release();
// Now set new trackable object // Now set new trackable object
if ( pobj ) if ( pobj )
{ {
wxTrackableBase *pt = wxTrackableCaster<T,wxHasBase<T,wxTrackableBase>::value >::Cast(pobj); // Add ourselves to object tracker list
if( pt ) wxTrackable *pt = dynamic_cast<wxTrackable*>(pobj);
if ( pt )
{ {
pt->AddNode( this ); pt->AddNode(this);
m_pobj = pobj; m_pobj = pobj;
} }
else else
{ {
// If the tracked we want to track does not support wxTackableBase, then // If the object we want to track does not support wxTackable, then
// log a message and keep the NULL object pointer. // log a message and keep the NULL object pointer.
wxLogWarning( _T("wxWeakRef::Assign - Type does not provide wxTrackableBase - resetting tracked object") ); wxFAIL_MSG( "Tracked class should inherit from wxTrackable" );
} }
} }
} }
void AssignCopy(const wxWeakRefDynamic& wr)
{
Assign(wr.m_pobj);
}
virtual void OnObjectDestroy()
{
wxASSERT_MSG( m_pobj, "tracked object should have removed us itself" );
m_pobj = NULL;
}
T *m_pobj; T *m_pobj;
}; };
// Provide some basic types of weak references // Provide some basic types of weak references
class WXDLLIMPEXP_FWD_BASE wxObject;
class WXDLLIMPEXP_FWD_BASE wxEvtHandler; class WXDLLIMPEXP_FWD_BASE wxEvtHandler;
class WXDLLIMPEXP_FWD_CORE wxWindow; class WXDLLIMPEXP_FWD_BASE wxWindow;
typedef wxWeakRef<wxObject> wxObjectRef;
typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef; typedef wxWeakRef<wxEvtHandler> wxEvtHandlerRef;
typedef wxWeakRef<wxWindow> wxWindowRef; typedef wxWeakRef<wxWindow> wxWindowRef;

View File

@@ -406,13 +406,15 @@ wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId)
wxString wxCommandEvent::GetString() const wxString wxCommandEvent::GetString() const
{ {
if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject) if (m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject)
{
return m_cmdString; return m_cmdString;
}
else else
{ {
#if wxUSE_TEXTCTRL #if wxUSE_TEXTCTRL
wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl); wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl);
if(txt) if ( txt )
return txt->GetValue(); return txt->GetValue();
else else
#endif // wxUSE_TEXTCTRL #endif // wxUSE_TEXTCTRL
@@ -1012,44 +1014,6 @@ void wxEventHashTable::GrowEventTypeTable()
delete[] oldEventTypeTable; delete[] oldEventTypeTable;
} }
// ----------------------------------------------------------------------------
// wxEventConnectionRef
// ----------------------------------------------------------------------------
// Below functions are mostly short but kept in cpp file to simplify setting
// breakpoints (GDB)
wxEventConnectionRef::wxEventConnectionRef(wxEvtHandler *src, wxEvtHandler *sink)
: m_src(src), m_sink(sink), m_refCount(1)
{
wxASSERT( m_sink );
m_sink->AddNode( this );
}
wxEventConnectionRef::~wxEventConnectionRef()
{
}
void wxEventConnectionRef::OnObjectDestroy( )
{
if( m_src )
m_src->OnSinkDestroyed( m_sink );
// It is safe to delete this tracker object here
delete this;
}
void wxEventConnectionRef::DecRef( )
{
if( !--m_refCount )
{
// The sink holds the only external pointer to this object
if( m_sink )
m_sink->RemoveNode(this);
delete this;
}
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// wxEvtHandler // wxEvtHandler
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -1089,19 +1053,20 @@ wxEvtHandler::~wxEvtHandler()
{ {
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it; wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it;
// Remove ourselves from sink destructor notifications // Remove ourselves from sink destructor notifications
// (this has usually been been done, in wxTrackable destructor) // (this has usually been been done, in wxTrackable destructor)
wxEvtHandler *eventSink = entry->m_eventSink; wxEvtHandler *eventSink = entry->m_eventSink;
if( eventSink ) if ( eventSink )
{ {
wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink ); wxEventConnectionRef * const
if( pecr ) evtConnRef = FindRefInTrackerList(eventSink);
{ if ( evtConnRef )
eventSink->RemoveNode( pecr ); {
delete pecr; eventSink->RemoveNode(evtConnRef);
} delete evtConnRef;
}
} }
if (entry->m_callbackUserData) if (entry->m_callbackUserData)
delete entry->m_callbackUserData; delete entry->m_callbackUserData;
delete entry; delete entry;
@@ -1117,7 +1082,7 @@ wxEvtHandler::~wxEvtHandler()
if ( wxPendingEvents ) if ( wxPendingEvents )
{ {
#if wxUSE_THREADS #if wxUSE_THREADS
if(wxPendingEventsLocker) if (wxPendingEventsLocker)
wxENTER_CRIT_SECT(*wxPendingEventsLocker); wxENTER_CRIT_SECT(*wxPendingEventsLocker);
#endif #endif
@@ -1130,7 +1095,7 @@ wxEvtHandler::~wxEvtHandler()
//else: we weren't in this list at all, it's ok //else: we weren't in this list at all, it's ok
#if wxUSE_THREADS #if wxUSE_THREADS
if(wxPendingEventsLocker) if (wxPendingEventsLocker)
wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); wxLEAVE_CRIT_SECT(*wxPendingEventsLocker);
#endif #endif
} }
@@ -1401,15 +1366,15 @@ void wxEvtHandler::Connect( int id, int lastId,
// Insert at the front of the list so most recent additions are found first // Insert at the front of the list so most recent additions are found first
m_dynamicEvents->Insert( (wxObject*) entry ); m_dynamicEvents->Insert( (wxObject*) entry );
// Make sure we get to know when a sink is destroyed // Make sure we get to know when a sink is destroyed
if( eventSink ) if ( eventSink )
{ {
wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink ); wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
if( pecr ) if ( evtConnRef )
pecr->IncRef( ); evtConnRef->IncRef( );
else else
pecr = new wxEventConnectionRef(this,eventSink); evtConnRef = new wxEventConnectionRef(this, eventSink);
} }
} }
@@ -1422,11 +1387,11 @@ bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType,
return false; return false;
// Remove connection from tracker node (wxEventConnectionRef) // Remove connection from tracker node (wxEventConnectionRef)
if( eventSink ) if ( eventSink )
{ {
wxEventConnectionRef *pecr = FindRefInTrackerList( eventSink ); wxEventConnectionRef *evtConnRef = FindRefInTrackerList(eventSink);
if( pecr ) if ( evtConnRef )
pecr->DecRef( ); evtConnRef->DecRef();
} }
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); wxList::compatibility_iterator node = m_dynamicEvents->GetFirst();
@@ -1519,37 +1484,36 @@ void *wxEvtHandler::DoGetClientData() const
return m_clientData; return m_clientData;
} }
// A helper func to find an wxEventConnectionRef object // A helper to find an wxEventConnectionRef object
wxEventConnectionRef* wxEvtHandler::FindRefInTrackerList( wxEvtHandler *eventSink ) wxEventConnectionRef *
wxEvtHandler::FindRefInTrackerList(wxEvtHandler *eventSink)
{ {
wxASSERT(eventSink); for ( wxTrackerNode *node = eventSink->GetFirst(); node; node = node->m_nxt )
for( wxTrackerNode *ptn=eventSink->GetFirst(); ptn; ptn=ptn->m_nxt )
{ {
// Only want wxEventConnectionRef nodes here // we only want wxEventConnectionRef nodes here
if( ptn->GetType()!=wxTrackerNode::EventConnectionRef ) wxEventConnectionRef *evtConnRef = node->ToEventConnection();
continue; if ( evtConnRef && evtConnRef->m_src == this )
wxEventConnectionRef *pecr = static_cast<wxEventConnectionRef*>(ptn);
if( pecr && pecr->m_src==this )
{ {
wxASSERT( pecr->m_sink==eventSink ); wxASSERT( evtConnRef->m_sink==eventSink );
return pecr; return evtConnRef;
} }
} }
return NULL; return NULL;
} }
void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink ) void wxEvtHandler::OnSinkDestroyed( wxEvtHandler *sink )
{ {
wxASSERT(m_dynamicEvents); wxASSERT(m_dynamicEvents);
// remove all connections with this sink // remove all connections with this sink
wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(), node_nxt; wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(), node_nxt;
while (node) while (node)
{ {
wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData();
node_nxt = node->GetNext(); node_nxt = node->GetNext();
if( entry->m_eventSink==sink ) if ( entry->m_eventSink==sink )
{ {
if (entry->m_callbackUserData) if (entry->m_callbackUserData)
delete entry->m_callbackUserData; delete entry->m_callbackUserData;

View File

@@ -70,6 +70,8 @@
thread/queue.cpp thread/queue.cpp
uris/uris.cpp uris/uris.cpp
vectors/vectors.cpp vectors/vectors.cpp
weakref/evtconnection.cpp
weakref/weakref.cpp
</sources> </sources>
<wx-lib>net</wx-lib> <wx-lib>net</wx-lib>
<wx-lib>base</wx-lib> <wx-lib>base</wx-lib>

View File

@@ -0,0 +1,247 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/weakref/evtconnection.cpp
// Purpose: wxWeakRef<T> unit test
// Author: Arne Steinarson
// Created: 2008-01-10
// RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/event.h"
#include "wx/weakref.h"
static int gs_value = 0; // Increased by 1 by first object and 0x10000 by 2nd object
static wxObject *gs_psrc1;
static wxObject *gs_psrc2;
// We need some event types
const wxEventType wxEVT_TEST = wxNewEventType(),
wxEVT_TEST1 = wxNewEventType(),
wxEVT_TEST2 = wxNewEventType();
class wxTestEvent : public wxEvent
{
public:
wxTestEvent(wxEventType type = wxEVT_TEST) : wxEvent(0, type) { }
virtual wxEvent *Clone() const { return new wxTestEvent(GetEventType()); }
};
class wxTestSink : public wxEvtHandler
{
public:
void OnTestEvent(wxEvent& evt)
{
if ( evt.GetEventObject() == gs_psrc1 )
gs_value += 1;
else if ( evt.GetEventObject() == gs_psrc2 )
gs_value += 0x10000;
}
void OnTestEvent1(wxEvent& )
{
gs_value += 0x00100;
}
void OnTestEvent2(wxEvent&)
{
gs_value += 0x01000000;
}
};
// --------------------------------------------------------------------------
// test class
// --------------------------------------------------------------------------
class EvtConnectionTestCase : public CppUnit::TestCase
{
public:
EvtConnectionTestCase() {}
private:
CPPUNIT_TEST_SUITE( EvtConnectionTestCase );
CPPUNIT_TEST( SinkTest );
CPPUNIT_TEST( SourceDestroyTest );
CPPUNIT_TEST( MultiConnectionTest );
CPPUNIT_TEST_SUITE_END();
void SinkTest();
void SourceDestroyTest();
void MultiConnectionTest();
DECLARE_NO_COPY_CLASS(EvtConnectionTestCase)
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( EvtConnectionTestCase );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( EvtConnectionTestCase, "EvtConnectionTestCase" );
// Helpers
void DoConnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
NULL, &ts);
eh2.Connect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
NULL, &ts);
}
void DoDisconnect( wxEvtHandler& eh1, wxEvtHandler& eh2, wxTestSink& ts ){
eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
NULL, &ts);
eh2.Disconnect(wxEVT_TEST, (wxObjectEventFunction) &wxTestSink::OnTestEvent,
NULL, &ts);
}
void EvtConnectionTestCase::SinkTest()
{
// Let the sink be destroyed before the sources
// An event used below
wxTestEvent evt;
// Connect two event handlers to one sink
wxEvtHandler eh1, eh2;
gs_psrc1 = &eh1;
gs_psrc2 = &eh2;
{
wxTestSink ts;
CPPUNIT_ASSERT( !ts.GetFirst() );
DoConnect(eh1, eh2, ts);
DoDisconnect(eh1, eh2, ts);
DoConnect(eh1, eh2, ts);
// Fire events
evt.SetEventObject(&eh1);
eh1.ProcessEvent(evt);
evt.SetEventObject(&eh2);
eh2.ProcessEvent(evt);
// Make sure they were processed correctly
CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
}
// Fire events again, should be no sink connected now
gs_value = 0;
evt.SetEventObject(&eh1);
eh1.ProcessEvent( evt );
evt.SetEventObject(&eh2);
eh2.ProcessEvent( evt );
// Make sure no processing happened
CPPUNIT_ASSERT_EQUAL( 0, gs_value );
}
void EvtConnectionTestCase::SourceDestroyTest()
{
// Let the sources be destroyed before the sink
wxTestSink ts;
wxTestEvent evt;
{
wxEvtHandler eh1;
{
CPPUNIT_ASSERT( !ts.GetFirst() );
// Connect two event handlers to one sink
wxEvtHandler eh2;
gs_psrc1 = &eh1;
gs_psrc2 = &eh2;
DoConnect( eh1, eh2, ts );
// Fire events
gs_value = 0;
evt.SetEventObject(&eh1);
eh1.ProcessEvent( evt );
evt.SetEventObject(&eh2);
eh2.ProcessEvent( evt );
// Make sure they were processed correctly
CPPUNIT_ASSERT_EQUAL( 0x00010001, gs_value );
}
gs_value = 0;
evt.SetEventObject(&eh1);
eh1.ProcessEvent( evt );
// Make sure still connected
CPPUNIT_ASSERT_EQUAL( 0x00000001, gs_value );
}
CPPUNIT_ASSERT( !ts.GetFirst() );
}
void EvtConnectionTestCase::MultiConnectionTest()
{
// events used below
wxTestEvent evt;
wxTestEvent evt1(wxEVT_TEST1);
wxTestEvent evt2(wxEVT_TEST2);
// One source
wxEvtHandler eh1;
evt.SetEventObject(&eh1);
gs_psrc1 = NULL;
gs_psrc2 = &eh1;
{
// ...and one sink
wxTestSink ts;
eh1.Connect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
NULL, &ts);
eh1.Connect(wxEVT_TEST1, (wxObjectEventFunction)&wxTestSink::OnTestEvent1,
NULL, &ts);
eh1.Connect(wxEVT_TEST2, (wxObjectEventFunction)&wxTestSink::OnTestEvent2,
NULL, &ts);
// Generate events
gs_value = 0;
eh1.ProcessEvent(evt);
eh1.ProcessEvent(evt1);
eh1.ProcessEvent(evt2);
CPPUNIT_ASSERT( gs_value==0x01010100 );
{
// Declare weak references to the objects (using same list)
wxEvtHandlerRef re(&eh1), rs(&ts);
}
// And now destroyed
eh1.Disconnect(wxEVT_TEST, (wxObjectEventFunction)&wxTestSink::OnTestEvent,
NULL, &ts);
eh1.ProcessEvent(evt);
eh1.ProcessEvent(evt1);
eh1.ProcessEvent(evt2);
CPPUNIT_ASSERT_EQUAL( 0x02010200, gs_value );
}
// No connection should be left now
gs_value = 0;
eh1.ProcessEvent(evt);
eh1.ProcessEvent(evt1);
eh1.ProcessEvent(evt2);
// Nothing should have been done
CPPUNIT_ASSERT_EQUAL( 0, gs_value );
}

281
tests/weakref/weakref.cpp Normal file
View File

@@ -0,0 +1,281 @@
///////////////////////////////////////////////////////////////////////////////
// Name: tests/weakref/weakref.cpp
// Purpose: wxWeakRef<T> unit test
// Author: Arne Steinarson
// Created: 2008-01-10
// RCS-ID: $Id$
// Copyright: (c) 2007 Arne Steinarson
///////////////////////////////////////////////////////////////////////////////
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
#include "testprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif // WX_PRECOMP
#include "wx/event.h"
#include "wx/weakref.h"
// A statically trackable derived wxObject
class wxObjectTrackable : public wxObject, public wxTrackable
{
public:
// Test member access
void TestFunc(){ }
// Make sure this does not clash with wxTrackableBase method
int GetFirst() { return 0; }
};
// --------------------------------------------------------------------------
// test class
// --------------------------------------------------------------------------
class WeakRefTestCase : public CppUnit::TestCase
{
public:
WeakRefTestCase() {}
private:
CPPUNIT_TEST_SUITE( WeakRefTestCase );
CPPUNIT_TEST( DeclareTest );
CPPUNIT_TEST( AssignTest );
CPPUNIT_TEST( AssignWeakRefTest );
CPPUNIT_TEST( MultiAssignTest );
CPPUNIT_TEST( CleanupTest );
CPPUNIT_TEST( DeleteTest );
#ifdef HAVE_DYNAMIC_CAST
CPPUNIT_TEST( DynamicRefTest );
#endif
CPPUNIT_TEST_SUITE_END();
void DeclareTest();
void AssignTest();
void AssignWeakRefTest();
void MultiAssignTest();
void CleanupTest();
void DeleteTest();
#ifdef HAVE_DYNAMIC_CAST
void DynamicRefTest();
#endif
DECLARE_NO_COPY_CLASS(WeakRefTestCase)
};
// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( WeakRefTestCase );
// also include in it's own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( WeakRefTestCase, "WeakRefTestCase" );
void WeakRefTestCase::DeclareTest()
{
{
wxObject o; // Should not work
wxEvtHandler eh;
wxObjectTrackable ot;
// Test declare when T is wxObject
// wxWeakRef<wxObject> wro1(&o); // Gives compile time failure
wxWeakRef<wxEvtHandler> wro2(&eh);
wxWeakRef<wxObjectTrackable> wro3(&ot);
CPPUNIT_ASSERT( wro2.get() == &eh );
CPPUNIT_ASSERT( wro3.get() == &ot );
// Test accessing wxObject members
CPPUNIT_ASSERT( !wro2->GetRefData() );
CPPUNIT_ASSERT( !wro3->GetRefData() );
wxWeakRef<wxEvtHandler> wreh(&eh);
wxWeakRef<wxObjectTrackable> wrot(&ot);
CPPUNIT_ASSERT( wreh.get() == &eh );
CPPUNIT_ASSERT( wrot.get() == &ot );
}
}
void WeakRefTestCase::AssignTest()
{
wxWeakRef<wxEvtHandler> wro1;
wxWeakRef<wxObjectTrackable> wro2;
{ // Scope for object destruction
wxEvtHandler eh;
wxObjectTrackable ot;
wro1 = &eh;
wro2 = &ot;
CPPUNIT_ASSERT( wro1.get() == &eh );
CPPUNIT_ASSERT( wro2.get() == &ot );
}
// Should be reset now
CPPUNIT_ASSERT( !wro1 );
CPPUNIT_ASSERT( !wro2 );
}
void WeakRefTestCase::AssignWeakRefTest()
{
// Test declare when T is wxObject
wxWeakRef<wxEvtHandler> wro1;
wxWeakRef<wxObjectTrackable> wro2;
{ // Scope for object destruction
wxEvtHandler eh;
wxObjectTrackable ot;
wxWeakRef<wxEvtHandler> wro3;
wxWeakRef<wxObjectTrackable> wro4;
wro1 = &eh;
wro2 = &ot;
wro3 = wro1;
wro4 = wro2;
CPPUNIT_ASSERT( wro1.get() == &eh );
CPPUNIT_ASSERT( wro2.get() == &ot );
CPPUNIT_ASSERT( wro3.get() == &eh );
CPPUNIT_ASSERT( wro4.get() == &ot );
wro4.Release();
CPPUNIT_ASSERT( !wro4.get() );
}
// Should be reset now
CPPUNIT_ASSERT( !wro1 );
CPPUNIT_ASSERT( !wro2 );
}
void WeakRefTestCase::MultiAssignTest()
{
// Object is tracked by several refs
wxEvtHandler *peh = new wxEvtHandler;
// Test declare when T is wxObject
wxWeakRef<wxEvtHandler> wro1(peh);
wxWeakRef<wxEvtHandler> wro2(peh);
wxObjectTrackable *pot = new wxObjectTrackable;
wxWeakRef<wxObjectTrackable> wro3 = pot;
wxWeakRef<wxObjectTrackable> wro4 = pot;
CPPUNIT_ASSERT( wro1.get() == peh );
CPPUNIT_ASSERT( wro2.get() == peh );
CPPUNIT_ASSERT( wro3.get() == pot );
CPPUNIT_ASSERT( wro4.get() == pot );
delete peh;
delete pot;
// Should be reset now
CPPUNIT_ASSERT( !wro1 );
CPPUNIT_ASSERT( !wro2 );
CPPUNIT_ASSERT( !wro3 );
CPPUNIT_ASSERT( !wro4 );
}
void WeakRefTestCase::CleanupTest()
{
// Make sure that trackable objects have no left over tracker nodes after use.
// This time the references goes out of scope before the objects.
wxEvtHandler eh;
wxObjectTrackable ots;
wxObjectTrackable otd;
{ // Scope for object destruction
wxWeakRef<wxEvtHandler> wro1;
wxWeakRef<wxEvtHandler> wro2;
wxWeakRef<wxObjectTrackable> wro3;
wxWeakRef<wxObjectTrackable> wro4;
wro1 = &eh;
wro2 = &eh; // Has two tracker nodes now
wro3 = &ots;
wro4 = &otd;
// Access members of reffed object
wro3->TestFunc();
CPPUNIT_ASSERT( eh.GetFirst()==&wro2 );
CPPUNIT_ASSERT( ots.wxTrackable::GetFirst()==&wro3 );
CPPUNIT_ASSERT( otd.wxTrackable::GetFirst()==&wro4 );
}
// Should be reset now
CPPUNIT_ASSERT( !eh.GetFirst() );
CPPUNIT_ASSERT( !ots.wxTrackable::GetFirst() );
CPPUNIT_ASSERT( !otd.wxTrackable::GetFirst() );
}
void WeakRefTestCase::DeleteTest()
{
// Object is tracked by several refs
wxEvtHandler *peh = new wxEvtHandler;
// Declared derived type of object and test deleting it
wxEvtHandlerRef wre(peh);
wxWeakRef<wxEvtHandler> wro(peh);
// test size of references (see that it has selected right base class)
#ifdef HAVE_PARTIAL_SPECIALIZATION
CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
CPPUNIT_ASSERT_EQUAL( sizeof(void*)*4, sizeof(wro) );
#else
CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wre) );
CPPUNIT_ASSERT_EQUAL( sizeof(void*)*3, sizeof(wro) );
#endif
CPPUNIT_ASSERT( wre.get() == peh );
CPPUNIT_ASSERT( wro.get() == peh );
delete wre.get();
CPPUNIT_ASSERT( !wre );
CPPUNIT_ASSERT( !wro );
}
#ifdef HAVE_DYNAMIC_CAST
void WeakRefTestCase::DynamicRefTest()
{
wxWeakRefDynamic<wxEvtHandler> wro1;
wxWeakRefDynamic<wxObjectTrackable> wro2;
wxWeakRefDynamic<wxObjectTrackable> wro3;
{ // Scope for object destruction
{
wxEvtHandler eh;
wro1 = &eh;
}
CPPUNIT_ASSERT( !wro1 );
wxObjectTrackable otd1;
wxObjectTrackable otd2;
wro2 = &otd1;
wro3 = &otd2;
CPPUNIT_ASSERT( wro2.get() == &otd1 );
CPPUNIT_ASSERT( wro3.get() == &otd2 );
wro3 = wro2;
CPPUNIT_ASSERT( wro2.get() == &otd1 );
CPPUNIT_ASSERT( wro3.get() == &otd1 );
}
// Should be reset now
CPPUNIT_ASSERT( !wro2 );
CPPUNIT_ASSERT( !wro3 );
}
#endif // HAVE_DYNAMIC_CAST