00001 #ifndef DYNOBJPTR_HPP
00002 #define DYNOBJPTR_HPP
00003
00004 #include "utils/Notifier.hpp"
00005 #include "DynObj.h"
00006 #include "DoError.h"
00007 #include "RefCount.h"
00008 #include "DORT.h"
00009 #include "DortInternal.h"
00010 #include "DoBase.hpp"
00011
00012
00029 template<class T>
00030 struct DynObjPtr : public NotifiableI {
00032 DynObjPtr( ) : m_pt(0), m_flags(0) { }
00033
00037 explicit DynObjPtr( T* pt, bool try_strong_ref=false ) : m_pt(0), m_flags(0), m_pni(0) {
00038 InternalAssign(pt,try_strong_ref);
00039 }
00041 explicit DynObjPtr( DynObjPtr& dop ) : m_pt(0), m_flags(0), m_pni(0) {
00042 InternalAssign(dop,dop.HasStrongRef());
00043 }
00044 ~DynObjPtr(){
00045 InternalRelease();
00046 }
00047
00050 DynObjPtr& operator = (T* pt){
00051 InternalRelease();
00052 InternalAssign( pt, false );
00053 return *this;
00054 }
00055
00058 DynObjPtr& operator = (DynObjPtr<T>& dop){
00059 return operator = (dop.Get());
00060 }
00061
00065 DynObjPtr& Assign( T* pt, bool try_strong_ref=false ){
00066 InternalRelease();
00067 bool r = InternalAssign( pt, try_strong_ref );
00068 return *this;
00069 }
00070
00071
00073 operator T* () { return m_pt; }
00075 operator T& () { return *m_pt; }
00077 T& operator * () { return *m_pt; }
00079 T* operator -> () { return m_pt; }
00081 T* Get() { return m_pt; }
00082
00083 enum{ isStatic=1, hasDoRef=2, hasWeakRef=4, hasStrongRef=8 };
00084
00086 bool HasStrongRef(){ return m_pt && m_flags&hasStrongRef; }
00087
00089 bool IsOk(){ return m_pt!=NULL; }
00090
00092 bool Release(){ T*pt=m_pt; InternalRelease(); return pt && !m_pt; }
00093
00094 protected:
00095
00096 bool InternalAssign( T* pt, int try_strong_ref ){
00097 DO_ASSERT_MSG(!m_pt,"T* m_pt should be NULL");
00098 if( !pt ) return true;
00099 m_flags = 0;
00100
00101 typename VBaseSelect<T>::type *pt1 = (typename VBaseSelect<T>::type*)pt;
00102 DO_ASSERT_MSG( ((void*)pt)==((void*)pt1), "VBaseSelect<T>::type should keep ptr representation" );
00103 DynObjType *pdt = ::doGetType( pt1 );
00104 if( !pdt ) return false;
00105
00106 DynObjType *pdt_outer = NULL;
00107
00108 if( doIsStatic(pt,pdt) ){
00109
00110 m_pt = pt;
00111 m_flags |= isStatic;
00112 return true;
00113 }
00114
00115
00116 RefCountI *prci = NULL;
00117 if( try_strong_ref ){
00118 prci = DoCasterSelect<T,RefCountI,DoIsTypeA<T,RefCountI>::v>::Cast(pt,pdt);
00119 if( prci ){
00120 prci->IncRef();
00121 m_flags |= hasStrongRef;
00122 m_pt = pt;
00123
00124 if( ::doIsMainObject(pt1,pdt)>0 ){
00125
00126 return true;
00127 }
00128 }
00129
00130 if( try_strong_ref==2 )
00131 return false;
00132 }
00133
00134
00135 NotifierI *pni = DoCasterSelect<T,NotifierI,DoIsTypeA<T,NotifierI>::v>::Cast(pt,pdt);
00136 if( pni ){
00137 if( !pni->AddNotifiable(this,NOT_EVT_DTOR) )
00138 goto Failed_ReleaseStrong;
00139 m_flags |= hasWeakRef;
00140 m_pni = pni;
00141 m_pt = pt;
00142 }
00143 else {
00144
00145 DortInternalI *pdorti = (DortInternalI*)doGetObj( &DORT, DORTINTERNALI_TYPE_ID );
00146 if( !pdorti ) goto Failed_ReleaseStrong;
00147 DynObj *pdo = DoCasterSelect<T,DynObj,DoIsTypeA<T,DynObj>::v>::Cast(pt,pdt);
00148 if( !pdo ) goto Failed_ReleaseStrong;
00149 if( !pdorti->TrackDynObj(pdo,this,true,pdt) )
00150 goto Failed_ReleaseStrong;
00151 m_flags |= hasDoRef;
00152 m_pdo = pdo;
00153 m_pt = pt;
00154 }
00155
00156 return true;
00157
00158 Failed_ReleaseStrong:
00159
00160 if( !try_strong_ref && InternalAssign(pt,2) )
00161 return true;
00162
00163
00164 if( prci ) {
00165 prci->DecRef();
00166 m_pt = NULL;
00167 }
00168 m_flags &= ~hasStrongRef;
00169 DO_ASSERT_MSG( !(m_flags&(hasDoRef|hasWeakRef|hasStrongRef)), "All ref flags should be cleared now" );
00170 return false;
00171 }
00172
00173 void InternalRelease(){
00174 if( m_pt ){
00175 DynObjType *pdt = ::doGetType( (typename VBaseSelect<T>::type*)m_pt );
00176
00177 if( m_flags&hasDoRef ){
00178 DortInternalI *pdorti = (DortInternalI*)doGetObj( &DORT, DORTINTERNALI_TYPE_ID );
00179 if( pdorti ){
00180 DO_ASSERT_MSG( m_pdo, "Should have store DynObj*" );
00181 m_flags &= ~hasDoRef;
00182 bool r = pdorti->TrackDynObj( m_pdo, this, false );
00183 DO_ASSERT_MSG(r,"Should succeed in removing tracker");
00184 }
00185 if( !pdorti )
00186 DO_LOG_ERR(DOERR_CANT_FIND_TYPE,"DynObjPtr::InternalRelease - Failed finding interface DortInternalI or DynObj");
00187 }
00188 if( m_flags&hasWeakRef ){
00189
00190 DO_ASSERT_MSG(m_pni,"Should have stored NotifierI*");
00191 m_flags &= ~hasWeakRef;
00192 bool r = m_pni->RemoveNotifiable(this,NOT_EVT_DTOR);
00193 DO_ASSERT_MSG(r,"Should succeed removing NotifiableI");
00194 }
00195
00196 if( m_flags&hasStrongRef ){
00197
00198 RefCountI *prci = DoCasterSelect<T,RefCountI,DoIsTypeA<T,RefCountI>::v>::Cast(m_pt,pdt);
00199 if( prci ){
00200 prci->DecRef();
00201 m_flags &= ~hasStrongRef;
00202 }
00203 else
00204 DO_LOG_ERR(DOERR_CANT_FIND_TYPE,"DynObjPtr::InternalRelease - Failed finding interface RefCountI");
00205 }
00206 if( m_flags&(hasDoRef|hasWeakRef|hasStrongRef) )
00207 DO_LOG_ERR( DOERR_CANT_FIND_TYPE, "DynObjPtr::InternalRelease - All ref flags should be cleared now" );
00208 m_pni = NULL;
00209 m_pt = NULL;
00210 }
00211 }
00212
00213
00214 virtual bool docall OnNotify( NotifierI *pni, int evt, NotifDataI *pnd ){
00215 bool is_ok_caller = false;
00216 if( evt==NOT_EVT_DTOR ){
00217 DO_ASSERT_MSG( m_flags&hasWeakRef && pni==m_pni, "Should match weak ref (NotrifierI) in OnNotify" );
00218 if( pni==m_pni )
00219 is_ok_caller = true;
00220 }
00221 else if( evt==NOT_EVT_ON_DYNOBJ_DESTROY ){
00222 NotifDataWithPtr *pndwp = do_cast<NotifDataWithPtr*>(pnd);
00223 if( pndwp ){
00224 DO_ASSERT_MSG( m_flags&hasDoRef && pndwp->m_pdi==m_pdo, "Should match weak ref (DynObj) in OnNotify" );
00225 if( pndwp->m_pdi==m_pdo )
00226 is_ok_caller = true;
00227 }
00228 }
00229 DO_ASSERT_MSG(m_pt,"Should have tracked object");
00230 DO_ASSERT_MSG(is_ok_caller,"Should have OK caller");
00231 if( !is_ok_caller )
00232 return false;
00233
00234 m_pt = NULL;
00235 m_flags &= ~(hasDoRef|hasWeakRef|hasStrongRef);
00236 return true;
00237 }
00238
00239 char m_flags;
00240 bool m_flag_unused2;
00241 bool m_flag_unused1;
00242 bool m_flag_unused;
00243
00244 T* m_pt;
00245 union {
00246 NotifierI *m_pni;
00247 DynObj *m_pdo;
00248 };
00249
00250
00251 };
00252
00253 #endif // DYNOBJPTR_HPP