base_nest.hh

Go to the documentation of this file.
00001 /*
00008  * LEGAL:   COPYRIGHT (C) 2006 JIM E. BROOKS
00009  *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
00010  *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
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;  // inner list (links items)
00087     typedef Dlink<T>            InnerDlink;  // link in inner list that points to actual object
00088     typedef Dlist<InnerDlist>   OuterDlist;  // outer list (links inner lists)
00089     typedef Dlink<InnerDlist>   OuterDlink;  // link in outer dlist that points to inner list
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() { }  // NOP, this doesn't own Dlist/Dlink
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 )  // eg groupId = false;
00119                     {
00120                         ASSERT( not f );  // assigning true is nonsensical
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;  // Nest<> should use Get*() methods
00146         OuterDlink*     mOuterDlink;  // which do checking
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() { }  // NOP, doesn't own the pointed-to objects
00168     private: InnerDlink* GetInnerDlink( void )  const { ASSERT(*this); return mInnerDlink; }
00169     public: void    operator=( bool f )  // eg itemId = false;
00170                     {
00171                         ASSERT( not f );  // assigning true is nonsensical
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;   // Nest<> should use Get*() methods which do checking
00188     friend class Nest<T>;
00189     };
00190 
00191 public:
00192     enum eDestroy { DESTROY = Dlist<T>::DESTROY,
00193                     KEEP    = Dlist<T>::KEEP };
00194 
00195     // OuterDlist always has DESTROY/SCALAR.
00196     // The user-specified destroy args apply to inner dlists.
00197     Nest( void )
00198     :   mDestroy(DESTROY),
00199         mOuterDlist(OuterDlist::DESTROY)
00200     {
00201         // NOP
00202     }
00203 
00204     Nest( eDestroy destroy )
00205     :   mDestroy(destroy),
00206         mOuterDlist(OuterDlist::DESTROY)  // independent of ctor arg
00207     {
00208         // NOP
00209     }
00210 
00211     ~Nest()
00212     {
00213         // NOP.  mOuterDlist destroys itself and its sub-lists.
00214         // Whether items are destroyed depends whether user passed DESTROY/KEEP.
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       //ASSERT( groupId );
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();  // invalid ID, no groups exist
00261         }
00262     }
00263 
00267     GroupId
00268     NextGroup( const GroupId& groupId ) const
00269     {
00270         ASSERT( groupId );  // valid ID must be passed
00271         ASSERT( not mOuterDlist.IfEmpty() );  // how could an ID be passed if none exists?
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         // Unlink item from inner list.
00308         // itemId has a GroupId which has inner list.
00309         InnerDlist* innerDlist = groupId.GetInnerDlist();
00310         innerDlist->Unlink( itemId.GetInnerDlink() );  // unlink item (doesn't delete item)
00311 
00312         // If inner list has become empty, unlink it out of outer list, and delete it.
00313         if ( innerDlist->IfEmpty() )
00314         {
00315             mOuterDlist.Unlink( groupId.GetOuterDlink() );
00316             delete innerDlist;
00317             groupId = false;  // invalidate
00318         }
00319 
00320         itemId = false;  // invalidate
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             // This group is empty.
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() );  // how can item ID be obtained from empty inner list?
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                 // Pass this item to functor.
00381                 functor( GetItem(itemId) );
00382 
00383                 // To next item.  Stop at circling back to first item.
00384                 itemId = NextItem( groupId, itemId );
00385                 if ( itemId == itemId1 ) break;
00386             }
00387             // To next group likewise.
00388             groupId = NextGroup( groupId );
00389             if ( groupId == groupId1 ) break;
00390         }
00391     }
00392 
00393 private:
00394     eDestroy    mDestroy;  // applies to inner Dlists
00395     OuterDlist  mOuterDlist;
00396 };
00397 
00398 } // namespace base
00399 
00400 #endif // BASE_NEST_HH
Palomino 3D Engine documents generated by doxygen 1.5.3 on Fri Nov 23 11:26:06 2007