notifiable.hpp

来自「The library provides supports for run-ti」· HPP 代码 · 共 271 行

HPP
271
字号
#ifndef NOTIFIABLE_HPP#define NOTIFIABLE_HPP// define NOTIF_SILENT to suppress warnings below#include "NotifiableI.hpp"#include "TemplUtils.hpp"// For compatibility with DynObj.h#ifndef docall	#ifndef NOTIF_SILENT		#warning docall not defined, defining to nothing	#endif	#define docall#endif// If threaded implementation, NOTIF_LOCK locks a global recursive mutex// so that NotifierI and Notifiable can decouple in an ordered way.#ifndef  NOTIF_LOCK    #include "pi/CritSect.h"    // Use a shared global in Notifiable.cpp    extern CritSect g_not_cs;	#define NOTIF_LOCK   g_not_cs.Enter()	#define NOTIF_UNLOCK g_not_cs.Leave()#endif #ifndef NOTIF_TRACE	#ifndef NOTIF_SILENT		#warning NOTIF_TRACE not defined, defining to nothing	#endif 	#define NOTIF_TRACE(str)#endif // Reader-write lock for WeakRef#include "pi/RWLock.h"class NotifLocker {public:	NotifLocker(){ NOTIF_LOCK; }	~NotifLocker(){ NOTIF_UNLOCK; }};// Helper struct, represents one subscriber to a specific notification.struct NotTarget {    NotTarget(NotifiableI* pni, int evt) : m_pni(pni), m_evt(evt) { }    NotTarget(const NotTarget& nt) : m_pni(nt.m_pni), m_evt(nt.m_evt) { }    NotifiableI *m_pni;    int m_evt;    bool operator == (const NotTarget& nt) { return nt.m_pni==m_pni && nt.m_evt==m_evt; }};/** @ingroup VObj  * Base class to include support for notfications. * A class that derives from Notifier send off destructor notifications * so we can have weak references to them. For thread safety, it uses a lock  * that is shared between all instances of Notifier. */class Notifier : public NotifierI {public:	Notifier() : m_fst(NULL) { }	~Notifier() {		Notify(NOT_EVT_DESTRUCTOR,NULL);		NotifLocker lock;		delete m_fst; 		m_fst=NULL; 	}    /** Adds a notifcation target to this object */	virtual bool docall AddNotifiable(NotifiableI* pnot, int evt){        if( !pnot ) return false;		NOTIF_TRACE("Adding notifiable");		NotifLocker lock;         // Only add once        if( TLLFind(NotTarget(pnot,evt),m_fst) ) return false;		m_fst=new TLLNode<NotTarget>(NotTarget(pnot,evt),m_fst);         return true;	}    /** Remove a notifcation target to this object */	virtual bool docall RemoveNotifiable(NotifiableI* pnot, int evt){ 		NOTIF_TRACE("Removing notifiable");		NotifLocker lock; 		return TLLErase<NotTarget>(NotTarget(pnot,evt),&m_fst); 	}    /** Notifies all notifcation targets registered with this object */	virtual int docall Notify( int evt, NotDataI *pnd ){		NotifLocker lock; 		// We send pointer to ourseleves as first arg        int cnt=0;		for( TLLNode<NotTarget> *pnode=m_fst; pnode; pnode=pnode->m_nxt )            if( pnode->m_t.m_evt==evt || pnode->m_t.m_evt==NOT_EVT_ALL )                cnt++, pnode->m_t.m_pni->OnNotify( this, evt, pnd );        return cnt;	}	protected:	TLLNode<NotTarget> *m_fst;};// The point with the below class is that it can convert back to the main class pointer// However, then we loose the type (NotifierI). The receiver can resolve type/*template<class T>class Notifier : public NotifierBaseImpl {public:	~Notifier(){ Notify(NOT_DESTRUCTOR,NULL); } 	virtual void docall Notify( int msg, NotDataI *pnd ){		NotifLocker lock;  		// NOTE: Conversion to T* will cast back to whole object (if multiple bases) 		// T and Notifier will be in the same object and on the same SDO side		T* pt = static_cast<T*>(this);		for( TLLNode<NotifiableI*> *pnode=m_fst; pnode; pnode=pnode->m_nxt )			pnode->m_t->OnNotify( pt, msg, pnd );	}};*//** @ingroup VObj  * Weak reference to another object of type T. * The other object must support NotifierI, otherwise we cannot  * make a reference. To generate a NotifierI from T, there is  * GenericCaster which by default uses static_cast<NotfierI*>(T*). * DynObj will specialize this to provide the interface in a  * different way (using do_cast). * A WeakRef can be used in a thread safe way, using HoldGet() and  * HoldPut(). It has a reader-writer lock object per instance, so * the reference cannot be overwritten nor destroyed while we do  * HoldGet(). */template<class T>	class WeakRef : public NotifiableI {public:	WeakRef(T* pobj=NULL) : m_pobj(NULL), m_pni(NULL) { Reset(pobj); }	~WeakRef(){ Reset(NULL); NOTIF_TRACE("WeakRef Dtor"); }    /** Set the reference to another object */	WeakRef& Reset( T* pobj ){         piWriteLocker<RWLock> locker( m_lock );        if( m_pobj==pobj ) return *this;                assert( locker.Locked() );        if( m_pni || m_pobj ){            assert( m_pni && m_pobj );            m_pni->RemoveNotifiable(this,NOT_EVT_DESTRUCTOR);            m_pni = NULL; m_pobj = NULL;        }        if( !pobj ) return *this;                // This will use a static_cast if available and if not, it can be         // specialized (with value 1)		m_pni = GenericCaster<NotifierI*,T*,                            1-IsConvertible<NotifierI*,T*>::v>::Cast(pobj);        if( !m_pni ){			NOTIF_TRACE("WeakRef::Reset - Could not cast to object to NotifierI. Resetting object.");            m_pobj = NULL;            return *this;        }        m_pobj = pobj;		m_pni->AddNotifiable(this,NOT_EVT_DESTRUCTOR);        return *this;	}	    /** Operator support */	WeakRef&  operator = (T *pobj){ return Reset(pobj); }    bool operator ==(T *pobj){ return m_pobj==pobj; }	/** These are non-synced methods. Only use from the same thread as where      * the reference owner. */	operator T*(){ return m_pobj; }    /** Non-synced */	T* operator ->(){ return m_pobj; }    /** Non-synced */	T* Get(){ return m_pobj; }    /** Return true if the reference is empty (we have NULL pointer) */    bool operator!(){ return !m_pobj; }        /** Synchronized access.      * This increases read counter (and must be compensated with HoldPut) */    T* HoldGet(){         if( !m_pobj ) return NULL;        if( !m_lock.Lock() )             return NULL;        return m_pobj;    }	    /** Synchronized end-of-access.      * This decreases read counter. On zero, the reference can be modified. */    void HoldPut( T *pt ){         if( !pt ) return;        assert( pt==m_pobj );        bool b = m_lock.Unlock();        assert( b );    }    protected:	virtual bool docall OnNotify( NotifierI *psrc, int evt, NotDataI *pnd ){		if( evt==NOT_EVT_DESTRUCTOR ){            piWriteLocker<RWLock> locker(m_lock);            if( psrc!=m_pni ){				NOTIF_TRACE("WeakRef::OnNotify: Unknown source, keeping object");                 return false;            }            m_pobj = NULL;            m_pni = NULL;            return true;		}		else{			NOTIF_TRACE("WeakRef::OnNotify: Unknown event, doing nothing"); 			return false;		}	}		T* m_pobj;          // 16 bytes all in all    NotifierI *m_pni;    RWLock m_lock;};/*// The difference compared to WeakRef is that here we don't keep a// pointer to the compound object, instead we have a pointer to // a sub object. We cannot do the 'inside' test, but have to // explicitely store a pointer to the NotifierI. template<class T>	class WeakRefSubObject : public WeakRef<T> {public:	WeakRefSubObject(T* pobj=NULL) : WeakRef<T>(pobj), m_pni(NULL) { }	~WeakRefSubObject(){  }		void Reset(T* pobj ){		NotifLocker lock;	// # Recursive lock!		WeakRef<T>::Reset( pobj );		if( this->m_pobj )			m_pni = Cast<NotifierI*>(this->m_pobj,NULL);	}		void operator = (T *pobj){ Reset(pobj); }		virtual bool docall OnNotify( NotifierI *psrc, int evt, NotDataI *pnd ){		NotifLocker lock;		if( evt==NOT_DESTRUCTOR ){			if( psrc==m_pni ){				this->m_pobj = NULL; 				m_pni=NULL;				NOTIF_TRACE("WeakRefSubObject::OnNotify: Releasing"); 				return true;			}			else{				NOTIF_TRACE("WeakRefSubObject::OnNotify: Unknown source, releasing reference anyway"); 				this->m_pobj = NULL; 				m_pni=NULL;				return false;			}		}		else{			NOTIF_TRACE("WeakRefSubObject::OnNotify: Unknown event, doing nothing"); 			return false;		}	}	protected:	NotifierI *m_pni;};*/#endif // NOTIFIABLE_HPP

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?