목차

include/AK/Tools/Common/AkListBare.h

Go to the documentation of this file.
00001 
00002 //
00003 // Copyright (c) 2006 Audiokinetic Inc. / All Rights Reserved
00004 //
00006 
00007 // AkListBare.h
00008 
00009 #ifndef _AKLISTBARE_H
00010 #define _AKLISTBARE_H
00011 
00012 // this one lets you define the structure
00013 // only requirement is that T must have member pNextItem (if using the default AkListBareNextItem policy struct).
00014 // client is responsible for allocation/deallocation of T.
00015 
00016 // WATCH OUT !
00017 // - remember that removeall/term can't delete the elements for you.
00018 // - be sure to destroy elements AFTER removing them from the list, as remove will
00019 // access members of the element.
00020 
00021 /* Usage: List of AkMyType.
00022 
00023 - With default AkMyType::pNextItem, no count (Length() is not available):
00024 typedef AkListBare<AkMyType> AkMyList1;
00025 
00026 - With custom AkMyType::pNextItemCustom, no count:
00027 struct AkListBareNextItemCustom
00028 {
00029     static AkForceInline AkMyType *& Get( AkMyType * in_pItem ) 
00030     {
00031         return in_pItem->pNextItemCustom;
00032     }
00033 };
00034 typedef AkListBare<AkMyType,AkListBareNextItemCustom> AkMyList2;
00035 
00036 - With default AkMyType::pNextItem, WITH count (Length() is available):
00037 typedef AkListBare<AkMyType,AkListBareNextItem,AkCountPolicyWithCount> AkMyList3;
00038 
00039 */
00040 
00041 //
00042 // List bare policy classes.
00043 //
00044 
00046 template <class T> struct AkListBareNextItem
00047 {
00049     static AkForceInline T *& Get( T * in_pItem ) 
00050     {
00051         return in_pItem->pNextItem;
00052     }
00053 };
00054 
00057 template <class T> 
00058 class AkCountPolicyNoCount
00059 {
00060 protected:
00061     AkForceInline void ResetCount( T* ) {}
00062     AkForceInline void IncrementCount( T* ) {}
00063     AkForceInline void DecrementCount( T* ) {}
00064 };
00065 
00066 template <class T> 
00067 class AkCountPolicyWithCount
00068 {
00069 public:
00071     AkForceInline unsigned int Length() const
00072     {
00073         return m_ulNumListItems;
00074     }
00075 
00076 protected:
00077     AkCountPolicyWithCount() :m_ulNumListItems( 0 ) {}
00078 
00079     AkForceInline void ResetCount( T* ) { m_ulNumListItems = 0; }
00080     AkForceInline void IncrementCount( T* ) { ++m_ulNumListItems; }
00081     AkForceInline void DecrementCount( T* ) { --m_ulNumListItems; }
00082 
00083 private:
00084     unsigned int    m_ulNumListItems;           
00085 };
00086 
00089 template <class T> 
00090 class AkLastPolicyWithLast
00091 {
00092 public:
00094     AkForceInline T * Last()
00095     {
00096         return m_pLast;
00097     }
00098 
00099 protected:
00100     AkForceInline AkLastPolicyWithLast() : m_pLast( NULL ) {}
00101 
00102     // Policy interface:
00103     // UpdateLast() is called by host to inform the policy that it should set the last item to a new value.
00104     // The policy is thus free to do what it wants. On the other hand, SetLast() must make sense for the user of the list,
00105     // otherwise it must not be implemented.
00106     AkForceInline void UpdateLast( T * in_pLast ) { m_pLast = in_pLast; }
00107     AkForceInline void SetLast( T * in_pLast ) { m_pLast = in_pLast; }
00108     AkForceInline void RemoveItem( T * in_pItem, T * in_pPrevItem )
00109     {
00110         // Is it the last one ?
00111         if( in_pItem == m_pLast )
00112         {
00113             // new last one is the previous one
00114             m_pLast = in_pPrevItem;
00115         }
00116     }
00117     AkForceInline void AddItem( T * in_pItem, T * in_pNextItem )
00118     {
00119         // Update tail.
00120         // Note: will never occur since it is used with iteratorEx (have EndEx?).
00121         if ( in_pNextItem == NULL )   
00122             m_pLast = in_pItem;
00123     }
00124 
00125 protected:
00126     T *             m_pLast;                    
00127 };
00128 
00129 template <class T> 
00130 class AkLastPolicyNoLast
00131 {
00132 protected:
00133     // Policy interface:
00134     // UpdateLast() is called by host to inform the policy that it should set the last item to a new value.
00135     // The policy is thus free to do what it wants. On the other hand, SetLast() must make sense for the user of the list,
00136     // otherwise it must not be implemented.
00137     AkForceInline void UpdateLast( T * ) {}
00138     // SetLast is voluntarily left undefined so that calling AkListBare::AddLast() with this policy results in a compile-time error.
00139     //AkForceInline void SetLast( T * in_pLast );
00140     AkForceInline void RemoveItem( T *, T * ) {}
00141     AkForceInline void AddItem( T *, T * ) {}
00142 };
00143 
00144 
00146 template <class T, template <class> class U_NEXTITEM = AkListBareNextItem, template <class> class COUNT_POLICY = AkCountPolicyNoCount, template <class> class LAST_POLICY = AkLastPolicyWithLast > class AkListBare : public COUNT_POLICY< T >, public LAST_POLICY< T >
00147 {
00148 public:
00150     struct Iterator
00151     {
00152         T* pItem;   
00153 
00155         inline Iterator& operator++()
00156         {
00157             AKASSERT( pItem );
00158             pItem = U_NEXTITEM<T>::Get( pItem );
00159             return *this;
00160         }
00161 
00163         inline T * operator*() const
00164         {
00165             AKASSERT( pItem );
00166             return pItem;
00167         }
00168 
00170         bool operator !=( const Iterator& in_rOp ) const
00171         {
00172             return ( pItem != in_rOp.pItem );
00173         }
00174         
00176         bool operator ==( const Iterator& in_rOp ) const
00177         {
00178             return ( pItem == in_rOp.pItem );
00179         }
00180     };
00181 
00184     struct IteratorEx : public Iterator
00185     {
00186         T* pPrevItem;   
00187 
00189         IteratorEx& operator++()
00190         {
00191             AKASSERT( this->pItem );
00192             
00193             pPrevItem = this->pItem;
00194             this->pItem = U_NEXTITEM<T>::Get( this->pItem );
00195             
00196             return *this;
00197         }
00198     };
00199 
00201     IteratorEx Erase( const IteratorEx& in_rIter )
00202     {
00203         IteratorEx returnedIt;
00204         returnedIt.pItem = U_NEXTITEM<T>::Get( in_rIter.pItem );
00205         returnedIt.pPrevItem = in_rIter.pPrevItem;
00206 
00207         RemoveItem( in_rIter.pItem, in_rIter.pPrevItem );
00208 
00209         return returnedIt;
00210     }
00211 
00213     IteratorEx Insert( const IteratorEx& in_rIter,
00214                        T * in_pItem )
00215     {
00216         IteratorEx returnedIt;
00217         AddItem( in_pItem, in_rIter.pItem, in_rIter.pPrevItem );
00218         returnedIt = in_rIter;
00219         returnedIt.pPrevItem = in_pItem;
00220         return returnedIt;
00221     }
00222 
00224     inline Iterator End()
00225     {
00226         Iterator returnedIt;
00227         returnedIt.pItem = NULL;
00228         return returnedIt;
00229     }
00230 
00232     inline IteratorEx BeginEx()
00233     {
00234         IteratorEx returnedIt;
00235         
00236         returnedIt.pItem = m_pFirst;
00237         returnedIt.pPrevItem = NULL;
00238         
00239         return returnedIt;
00240     }
00241 
00243     inline Iterator Begin()
00244     {
00245         Iterator returnedIt;
00246         
00247         returnedIt.pItem = m_pFirst;
00248         
00249         return returnedIt;
00250     }
00251 
00253     inline IteratorEx FindEx( T *  in_pItem )
00254     {
00255         IteratorEx it = BeginEx();
00256         for ( ; it != End(); ++it )
00257         {
00258             if ( it.pItem == in_pItem )
00259                 break;
00260         }
00261 
00262         return it;
00263     }
00264 
00266     AkListBare()
00267     : m_pFirst( NULL )
00268     {
00269     }
00270     
00272     ~AkListBare()
00273     {
00274     }
00275 
00277     void Term()
00278     {
00279         RemoveAll();
00280     }
00281 
00283     void AddFirst( T * in_pItem )
00284     {
00285         if ( m_pFirst == NULL )
00286         {
00287             m_pFirst = in_pItem;
00288             LAST_POLICY<T>::UpdateLast( in_pItem );
00289             U_NEXTITEM<T>::Get( in_pItem ) = NULL;
00290         }
00291         else
00292         {
00293             U_NEXTITEM<T>::Get( in_pItem ) = m_pFirst;
00294             m_pFirst = in_pItem;
00295         }
00296 
00297         COUNT_POLICY<T>::IncrementCount( in_pItem );
00298     }
00299 
00301     void AddLast( T * in_pItem )
00302     {
00303         U_NEXTITEM<T>::Get( in_pItem ) = NULL;
00304 
00305         if ( m_pFirst == NULL )
00306         {
00307             m_pFirst = in_pItem;
00308         }
00309         else
00310         {
00311             U_NEXTITEM<T>::Get( LAST_POLICY<T>::Last() ) = in_pItem;
00312         }
00313 
00314         LAST_POLICY<T>::SetLast( in_pItem );
00315 
00316         COUNT_POLICY<T>::IncrementCount( in_pItem );
00317     }
00318 
00320     AKRESULT Remove( T * in_pItem )
00321     {
00322         IteratorEx it = FindEx( in_pItem );
00323         if ( it != End() )
00324         {
00325             Erase( it );
00326             return AK_Success;
00327         }
00328 
00329         return AK_Fail;
00330     }
00331 
00333     AKRESULT RemoveFirst()
00334     {
00335         if( m_pFirst == NULL )
00336             return AK_Fail;
00337 
00338         if ( U_NEXTITEM<T>::Get( m_pFirst ) == NULL )
00339         {
00340             m_pFirst = NULL;
00341             LAST_POLICY<T>::UpdateLast( NULL );
00342         }
00343         else
00344         {
00345             m_pFirst = U_NEXTITEM<T>::Get( m_pFirst );
00346         }
00347 
00348         COUNT_POLICY<T>::DecrementCount( m_pFirst );
00349 
00350         return AK_Success;
00351     }
00352 
00354     AkForceInline void RemoveAll()
00355     {
00356         // Items being externally managed, all we need to do here is clear our members.
00357         m_pFirst = NULL;
00358         LAST_POLICY<T>::UpdateLast( NULL );
00359         COUNT_POLICY<T>::ResetCount( m_pFirst );
00360     }
00361 
00363     AkForceInline T * First()
00364     {
00365         return m_pFirst;
00366     }
00367 
00369     AkForceInline bool IsEmpty() const
00370     {
00371         return m_pFirst == NULL;
00372     }
00373 
00375     void RemoveItem( T * in_pItem, T * in_pPrevItem )
00376     {
00377         // Is it the first one ?
00378 
00379         if( in_pItem == m_pFirst )
00380         {
00381             // new first one is the next one
00382             m_pFirst = U_NEXTITEM<T>::Get( in_pItem );
00383         }
00384         else
00385         {
00386             // take it out of the used space
00387             U_NEXTITEM<T>::Get( in_pPrevItem ) = U_NEXTITEM<T>::Get( in_pItem );
00388         }
00389 
00390         LAST_POLICY<T>::RemoveItem( in_pItem, in_pPrevItem );
00391 
00392         COUNT_POLICY<T>::DecrementCount( m_pFirst );
00393     }
00394 
00396     void AddItem( T * in_pItem, T * in_pNextItem, T * in_pPrevItem )
00397     {
00398         U_NEXTITEM<T>::Get( in_pItem ) = in_pNextItem;
00399 
00400         if ( in_pPrevItem == NULL )
00401             m_pFirst = in_pItem;
00402         else
00403             U_NEXTITEM<T>::Get( in_pPrevItem ) = in_pItem;
00404 
00405         LAST_POLICY<T>::AddItem( in_pItem, in_pNextItem );
00406         
00407         COUNT_POLICY<T>::IncrementCount( in_pItem );
00408     }
00409 
00410 protected:
00411     T *             m_pFirst;                   
00412 };
00413 
00414 #endif // _AKLISTBARE_H