00001
00011
00012
00013
00014
00015
00016 #ifndef BASE_DLIST_HH
00017 #define BASE_DLIST_HH 1
00018
00019 namespace base {
00020
00021 template<typename T,typename LOCK> class Dlist;
00022 template<typename T,typename LOCK> class DlistIterator;
00023
00032 template<typename T,typename LOCK=FastLock>
00033 class Dlink
00034 {
00035
00036 friend class Dlist<T,LOCK>;
00037 private:
00038
00039 Dlink( void ) { SET_TYPESIG( this, TYPESIG_DLINK ); }
00040 ~Dlink() { INVALIDATE_TYPESIG( this, TYPESIG_DLINK ); }
00041 Dlink* mPrev;
00042 Dlink* mNext;
00043 T* mObj;
00044 public:
00045
00046 T* Obj( void ) const { CHECK_TYPESIG(this,TYPESIG_DLINK); return mObj; }
00047
00048 };
00049
00138 template<typename T,typename LOCK=FastLock>
00139 class Dlist : public Shared, public SemiThreadable
00140 {
00141
00142
00143
00144
00145 #define DLIST_SENTINEL_NULL_OBJ (reinterpret_cast<T*>(ILLEGAL_PTR))
00146
00147
00148 #define CHECK_DLIST_HEAD_TAIL() \
00149 CHECK_TYPESIG( mHead, TYPESIG_DLINK ); \
00150 CHECK_TYPESIG( mTail, TYPESIG_DLINK ); \
00151 ASSERT( mHead->mObj == DLIST_SENTINEL_NULL_OBJ );
00152
00153 public:
00154 enum eDestroy { DESTROY, KEEP };
00155
00156 public:
00160 Dlist( eDestroy destroy = DESTROY )
00161 {
00162
00163 THREAD_CODE( mInstanceLock = new LOCK; )
00164
00165 SET_TYPESIG( this, TYPESIG_DLIST );
00166
00167 mDestroy = destroy;
00168
00169
00170 mHead = mTail = new Dlink<T>;
00171 mHead->mObj = DLIST_SENTINEL_NULL_OBJ;
00172 mHead->mPrev = mHead->mNext = mTail->mPrev = mTail->mNext = mHead;
00173 }
00174
00175 public:
00180 ~Dlist()
00181 {
00182 Clear();
00183 delete mHead;
00184 THREAD_CODE( delete mInstanceLock; )
00185 INVALIDATE_TYPESIG( this, TYPESIG_DLIST );
00186 }
00187
00188 public:
00193 void
00194 Clear( void )
00195 {
00196 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00197
00198
00199
00200 Dlink<T>* dlink = mHead->mNext;
00201 while ( dlink != dlink->mNext )
00202 {
00203
00204 CHECK_TYPESIG(dlink,TYPESIG_DLINK);
00205 CHECK_TYPESIG(dlink->mNext,TYPESIG_DLINK);
00206
00207 Dlink<T>* next = dlink->mNext;
00208 if ( mDestroy == DESTROY )
00209 delete dlink->mObj;
00210 Unlink( dlink );
00211 dlink = next;
00212 }
00213 ASSERT( mHead == mTail );
00214 CHECK_DLIST_HEAD_TAIL();
00215 }
00216
00217 public:
00224 Dlink<T>*
00225 Prepend( T* obj )
00226 {
00227 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00228
00229 CHECK_DLIST_HEAD_TAIL();
00230
00231
00232
00233
00234
00235 Dlink<T>* dlink = new Dlink<T>;
00236
00237
00238 if ( UX(mHead == mTail) ) mTail = dlink;
00239 dlink->mNext = mHead->mNext;
00240 dlink->mPrev = mHead;
00241 dlink->mObj = obj;
00242 mHead->mNext = dlink->mNext->mPrev = dlink;
00243 CHECK_TYPESIG(dlink->mNext,TYPESIG_DLINK);
00244 CHECK_TYPESIG(dlink->mPrev,TYPESIG_DLINK);
00245 CHECK_DLIST_HEAD_TAIL();
00246 return dlink;
00247 }
00248
00249 public:
00255 Dlink<T>*
00256 Append( T* obj )
00257 {
00258 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00259
00260 CHECK_DLIST_HEAD_TAIL();
00261
00262
00263
00264
00265 Dlink<T>* dlink = new Dlink<T>;
00266
00267
00268 dlink->mPrev = mTail;
00269 dlink->mNext = mTail->mNext;
00270 dlink->mObj = obj;
00271 mTail->mNext = dlink;
00272 mTail = dlink;
00273 mHead->mPrev = dlink;
00274 CHECK_TYPESIG(dlink->mNext,TYPESIG_DLINK);
00275 CHECK_TYPESIG(dlink->mPrev,TYPESIG_DLINK);
00276 CHECK_DLIST_HEAD_TAIL();
00277
00278 return dlink;
00279 }
00280
00281 public:
00288 void
00289 Unlink( Dlink<T>* dlink )
00290 {
00291 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00292
00293 CHECK_TYPESIG( dlink, TYPESIG_DLINK );
00294 CHECK_DLIST_HEAD_TAIL();
00295
00296
00297
00298 if ( UX(mTail == dlink) ) mTail = dlink->mPrev;
00299 CHECK_TYPESIG(dlink->mNext,TYPESIG_DLINK);
00300 CHECK_TYPESIG(dlink->mPrev,TYPESIG_DLINK);
00301 dlink->mPrev->mNext = dlink->mNext;
00302 dlink->mNext->mPrev = dlink->mPrev;
00303 delete dlink;
00304 CHECK_DLIST_HEAD_TAIL();
00305 }
00306
00307 public:
00311 bool
00312 IfEmpty( void ) const
00313 {
00314 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00315
00316 CHECK_DLIST_HEAD_TAIL();
00317
00318 return mHead == mTail;
00319 }
00320
00321 public:
00325 bool
00326 IfMoreThanOne( void ) const
00327 {
00328 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00329
00330 CHECK_DLIST_HEAD_TAIL();
00331
00332
00333 return mHead->mNext != mHead
00334 && mHead->mNext->mNext != mHead;
00335 }
00336
00337 public:
00341 Dlink<T>*
00342 First( void ) const
00343 {
00344 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00345
00346 CHECK_DLIST_HEAD_TAIL();
00347 CHECK_TYPESIG(mHead->mNext,TYPESIG_DLINK);
00348
00349 return mHead == mTail ? NULL : mHead->mNext;
00350 }
00351
00352 public:
00356 Dlink<T>*
00357 Last( void ) const
00358 {
00359 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00360
00361 CHECK_DLIST_HEAD_TAIL();
00362
00363 return mHead == mTail ? NULL : mTail;
00364 }
00365
00366 public:
00370 Dlink<T>*
00371 Prev( const Dlink<T>* dlink ) const
00372 {
00373 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00374
00375 CHECK_DLIST_HEAD_TAIL();
00376 CHECK_TYPESIG(dlink,TYPESIG_DLINK);
00377 CHECK_TYPESIG(dlink->mPrev,TYPESIG_DLINK);
00378 ASSERT( dlink != mHead );
00379 ASSERT( ! (dlink->mPrev == mHead && mHead->mPrev == mHead) );
00380
00381 return dlink->mPrev != mHead ? dlink->mPrev : mHead->mPrev;
00382 }
00383
00384 public:
00388 Dlink<T>*
00389 Next( const Dlink<T>* dlink ) const
00390 {
00391 THREAD_CODE( typename LOCK::Auto autolock( mInstanceLock ); )
00392
00393 CHECK_DLIST_HEAD_TAIL();
00394 CHECK_TYPESIG(dlink,TYPESIG_DLINK);
00395 CHECK_TYPESIG(dlink->mNext,TYPESIG_DLINK);
00396 ASSERT( dlink != mHead );
00397 ASSERT( ! (dlink->mNext == mHead && mHead->mNext == mHead) );
00398
00399 return dlink->mNext != mHead ? dlink->mNext : mHead->mNext;
00400 }
00401
00402 public:
00406 bool
00407 IfLinked( const T* obj )
00408 {
00409 Dlink<T>* first = First();
00410 if ( first != NULL )
00411 {
00412
00413
00414 Dlink<T>* lnk = first;
00415 do
00416 {
00417 if ( lnk->Obj() == obj )
00418 return true;
00419 lnk = Next( lnk );
00420 }
00421 while ( lnk != first );
00422 }
00423 return false;
00424 }
00425
00426 public:
00430 void Lock( void ) const
00431 {
00432 THREAD_CODE( mInstanceLock->Lock(); )
00433 }
00434
00435 void Unlock( void ) const
00436 {
00437 THREAD_CODE( mInstanceLock->Unlock(); )
00438 }
00439
00440 public:
00441 typedef LOCK LockType;
00442
00443 private:
00444 eDestroy mDestroy;
00445 Dlink<T>* mHead;
00446 Dlink<T>* mTail;
00447
00448
00449 THREAD_CODE( mutable LOCK* mInstanceLock; )
00450
00451 public:
00452
00453 friend class DlistIterator<T,LOCK>;
00454 };
00455
00467 template<typename T,typename LOCK=FastLock>
00468 class DlistIterator : public AbstractIterator< SafePtr<T> >
00469 {
00470 public:
00471 DlistIterator( const Dlist<T,LOCK>& dlist )
00472 : mDlist(dlist),
00473 mNext(NULL),
00474 mNextNext(dlist.First()),
00475 mLocked(false)
00476 {
00477 CHECK_TYPESIG(&mDlist,TYPESIG_DLIST);
00478
00479
00480 if ( mNextNext != NULL )
00481 {
00482 mDlist.Lock();
00483 mLocked = true;
00484 }
00485
00486
00487 }
00488
00489 ~DlistIterator()
00490 {
00491
00492
00493 if ( mLocked ) mDlist.Unlock();
00494 }
00495
00497 operator bool()
00498 {
00499
00500
00501 if ( mNextNext != NULL )
00502 {
00503 CHECK_TYPESIG(mNextNext,TYPESIG_DLINK);
00504
00505
00506 mNext = mNextNext;
00507
00508
00509
00510
00511 mNextNext = mDlist.Next( mNextNext );
00512 if ( UX( mNextNext == mDlist.First() ) )
00513 mNextNext = NULL;
00514 return true;
00515 }
00516 else
00517 {
00518
00519
00520 if ( mLocked )
00521 {
00522 mDlist.Unlock(); mLocked = false;
00523 }
00524 return false;
00525 }
00526 }
00527
00529 SafePtr<T>
00530 Next( void )
00531 {
00532 return mNext->Obj();
00533 }
00534
00535 private:
00536 const Dlist<T,LOCK>& mDlist;
00537 Dlink<T>* mNext;
00538 Dlink<T>* mNextNext;
00539 bool mLocked;
00540 };
00541
00542 }
00543
00544 #endif // BASE_DLIST_HH