00001
00008
00009
00010
00011
00012
00013 #ifndef BASE_NEST_HH
00014 #define BASE_NEST_HH 1
00015
00016 #include "base_common.hh"
00017
00018 namespace base {
00019
00082 template<typename T>
00083 class Nest
00084 {
00085 private:
00086 typedef Dlist<T> InnerDlist;
00087 typedef Dlink<T> InnerDlink;
00088 typedef Dlist<InnerDlist> OuterDlist;
00089 typedef Dlink<InnerDlist> OuterDlink;
00090
00091 public:
00104 class GroupId
00105 {
00106
00107 public: GroupId( void )
00108 : mInnerDlist(NULL),
00109 mOuterDlink(NULL)
00110 { }
00111 private: GroupId( InnerDlist* innerDlist, OuterDlink* outerDlink )
00112 : mInnerDlist(innerDlist),
00113 mOuterDlink(outerDlink)
00114 { }
00115 public: ~GroupId() { }
00116 private: InnerDlist* GetInnerDlist( void ) const { ASSERT(*this); return mInnerDlist; }
00117 private: OuterDlink* GetOuterDlink( void ) const { ASSERT(*this); return mOuterDlink; }
00118 public: void operator=( bool f )
00119 {
00120 ASSERT( not f );
00121 mInnerDlist = NULL;
00122 mOuterDlink = NULL;
00123 }
00124 public: operator bool() const
00125 {
00126 return mInnerDlist != NULL
00127 && mOuterDlink != NULL;
00128 }
00129 friend bool operator==( const GroupId& a, const GroupId& b )
00130 {
00131 return a.mInnerDlist == b.mInnerDlist
00132 && b.mOuterDlink == b.mOuterDlink;
00133 }
00134 friend bool operator!=( const GroupId& a, const GroupId& b )
00135 {
00136 return a.mInnerDlist != b.mInnerDlist
00137 || b.mOuterDlink != b.mOuterDlink;
00138 }
00139 public: bool IfEmpty( void ) const
00140 {
00141 ASSERT( *this );
00142 return mInnerDlist == NULL || mInnerDlist->IfEmpty();
00143 }
00144 private:
00145 InnerDlist* mInnerDlist;
00146 OuterDlink* mOuterDlink;
00147 friend class Nest<T>;
00148 };
00149
00150 public:
00160 class ItemId
00161 {
00162
00163 public: ItemId( void )
00164 : mInnerDlink(NULL) { }
00165 private: ItemId( InnerDlink* innerDlink )
00166 : mInnerDlink(innerDlink) { }
00167 public: ~ItemId() { }
00168 private: InnerDlink* GetInnerDlink( void ) const { ASSERT(*this); return mInnerDlink; }
00169 public: void operator=( bool f )
00170 {
00171 ASSERT( not f );
00172 mInnerDlink = NULL;
00173 }
00174 public: operator bool() const
00175 {
00176 return mInnerDlink != NULL;
00177 }
00178 friend bool operator==( const ItemId& a, const ItemId& b )
00179 {
00180 return a.mInnerDlink == b.mInnerDlink;
00181 }
00182 friend bool operator!=( const ItemId& a, const ItemId& b )
00183 {
00184 return a.mInnerDlink != b.mInnerDlink;
00185 }
00186 private:
00187 InnerDlink* mInnerDlink;
00188 friend class Nest<T>;
00189 };
00190
00191 public:
00192 enum eDestroy { DESTROY = Dlist<T>::DESTROY,
00193 KEEP = Dlist<T>::KEEP };
00194
00195
00196
00197 Nest( void )
00198 : mDestroy(DESTROY),
00199 mOuterDlist(OuterDlist::DESTROY)
00200 {
00201
00202 }
00203
00204 Nest( eDestroy destroy )
00205 : mDestroy(destroy),
00206 mOuterDlist(OuterDlist::DESTROY)
00207 {
00208
00209 }
00210
00211 ~Nest()
00212 {
00213
00214
00215 }
00216
00218 bool
00219 IfEmpty( void ) const
00220 {
00221 return mOuterDlist.IfEmpty();
00222 }
00223
00225 GroupId
00226 AddGroup( void )
00227 {
00228 InnerDlist* innerDlist = new InnerDlist( (typename InnerDlist::eDestroy)mDestroy );
00229 OuterDlink* outerDlink = mOuterDlist.Append( innerDlist );
00230 return GroupId( innerDlist, outerDlink );
00231 }
00232
00234 bool
00235 IfEmptyGroup( const GroupId& groupId ) const
00236 {
00237
00238 return groupId && groupId.IfEmpty();
00239 }
00240
00249 GroupId
00250 FirstGroup( void ) const
00251 {
00252 if ( not mOuterDlist.IfEmpty() )
00253 {
00254 InnerDlist* innerDlist = mOuterDlist.First()->Obj();
00255 OuterDlink* outerDlink = mOuterDlist.First();
00256 return GroupId( innerDlist, outerDlink );
00257 }
00258 else
00259 {
00260 return GroupId();
00261 }
00262 }
00263
00267 GroupId
00268 NextGroup( const GroupId& groupId ) const
00269 {
00270 ASSERT( groupId );
00271 ASSERT( not mOuterDlist.IfEmpty() );
00272 OuterDlink* outerDlink = groupId.GetOuterDlink();
00273 OuterDlink* nextOuterDlink = mOuterDlist.Next( outerDlink );
00274 InnerDlist* nextInnerDlist = nextOuterDlink->Obj();
00275 return GroupId( nextInnerDlist, nextOuterDlink );
00276 }
00277
00279 T*
00280 GetItem( const ItemId& itemId ) const
00281 {
00282 ASSERT( itemId );
00283 return itemId.GetInnerDlink()->Obj();
00284 }
00285
00288 ItemId
00289 AddItem( const GroupId& groupId, T* item )
00290 {
00291 ASSERT( groupId );
00292 InnerDlink* innerDlink = groupId.GetInnerDlist()->Append( item );
00293 return ItemId( innerDlink );
00294 }
00295
00301 void
00302 RemoveItem( GroupId& groupId, ItemId& itemId )
00303 {
00304 ASSERT( groupId );
00305 ASSERT( itemId );
00306
00307
00308
00309 InnerDlist* innerDlist = groupId.GetInnerDlist();
00310 innerDlist->Unlink( itemId.GetInnerDlink() );
00311
00312
00313 if ( innerDlist->IfEmpty() )
00314 {
00315 mOuterDlist.Unlink( groupId.GetOuterDlink() );
00316 delete innerDlist;
00317 groupId = false;
00318 }
00319
00320 itemId = false;
00321 }
00322
00325 ItemId
00326 FirstItem( const GroupId& groupId ) const
00327 {
00328 ASSERT( groupId );
00329 InnerDlist* innerDlist = groupId.GetInnerDlist();
00330 if ( not innerDlist->IfEmpty() )
00331 {
00332 InnerDlink* innerDlink = innerDlist->First();
00333 return ItemId(innerDlink);
00334 }
00335 else
00336 {
00337
00338 return ItemId();
00339 }
00340 }
00341
00347 ItemId
00348 NextItem( const GroupId& groupId, const ItemId& itemId ) const
00349 {
00350 ASSERT( groupId );
00351 ASSERT( itemId );
00352 InnerDlist* innerDlist = groupId.GetInnerDlist();
00353 ASSERT( not innerDlist->IfEmpty() );
00354 InnerDlink* nextInnerDlink = innerDlist->Next( itemId.GetInnerDlink() );
00355 return ItemId( nextInnerDlink );
00356 }
00357
00368 template<typename FUNCTOR>
00369 void
00370 ForEachItem( FUNCTOR& functor )
00371 {
00372 const GroupId groupId1 = FirstGroup();
00373 GroupId groupId = groupId1;
00374 while ( groupId )
00375 {
00376 const ItemId itemId1 = FirstItem( groupId );
00377 ItemId itemId = itemId1;
00378 while ( itemId )
00379 {
00380
00381 functor( GetItem(itemId) );
00382
00383
00384 itemId = NextItem( groupId, itemId );
00385 if ( itemId == itemId1 ) break;
00386 }
00387
00388 groupId = NextGroup( groupId );
00389 if ( groupId == groupId1 ) break;
00390 }
00391 }
00392
00393 private:
00394 eDestroy mDestroy;
00395 OuterDlist mOuterDlist;
00396 };
00397
00398 }
00399
00400 #endif // BASE_NEST_HH