windows-nt/Source/XPSP1/NT/shell/shell32/tlist.h
2020-09-26 16:20:57 +08:00

290 lines
6.2 KiB
C++

/* Template class for doing a simple linked list ...
*/
#ifndef _TLIST_H
#define _TLIST_H
// the enum marker that remembers the current position
typedef void * CLISTPOS;
// template class for providing a doubly linked of pointers to nodes
template< class NODETYPE >
class CList
{
protected:
struct CNode
{
NODETYPE * m_pData;
CNode * m_pPrev;
CNode * m_pNext;
};
public:
CList();
~CList();
CLISTPOS GetHeadPosition();
NODETYPE * GetNext( CLISTPOS & rpCurPos );
int GetCount();
void RemoveAt( CLISTPOS pPos );
void RemoveAll( void );
CLISTPOS FindIndex( int iIndex );
CLISTPOS AddTail( NODETYPE * pData );
CLISTPOS AddBefore( CLISTPOS pPos, NODETYPE * pData );
#ifdef DEBUG
void ValidateList();
#define VALIDATELIST() ValidateList()
#else
#define VALIDATELIST()
#endif
protected:
CNode * m_pHead;
CNode * m_pTail;
};
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CList<NODETYPE>::CList()
{
m_pHead = NULL;
m_pTail = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CList<NODETYPE>::~CList()
{
RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CLISTPOS CList<NODETYPE>::GetHeadPosition( )
{
return (CLISTPOS) m_pHead;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
NODETYPE * CList<NODETYPE>::GetNext( CLISTPOS & rpCurPos )
{
ASSERT( rpCurPos != NULL );
CNode * pCur = (CNode *) rpCurPos;
NODETYPE * pData = pCur->m_pData;
rpCurPos = (CLISTPOS) pCur->m_pNext;
return pData;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
int CList<NODETYPE>::GetCount()
{
int iLength = 0;
CNode * pCur = m_pHead;
while ( pCur != NULL )
{
pCur = pCur->m_pNext;
iLength ++;
}
return iLength;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
void CList<NODETYPE>::RemoveAt( CLISTPOS pPos )
{
ASSERT( pPos != NULL );
#ifdef _DEBUG
// scan the list to ensure the marker is valid....
CNode * pCur = m_pHead;
while ( pCur != NULL )
{
if ( pCur == (CNode *) pPos )
{
break;
}
pCur = pCur->m_pNext;
}
ASSERT( pCur != NULL )
#endif
CNode * pRealPos = (CNode *) pPos;
if ( pRealPos->m_pPrev == NULL )
{
// we are at the start of the list
m_pHead = pRealPos->m_pNext;
}
else
{
// link the prev one to the next one (bypassing this one)
pRealPos->m_pPrev->m_pNext = pRealPos->m_pNext;
}
if ( pRealPos->m_pNext == NULL )
{
// we are at the end of the list
m_pTail = pRealPos->m_pPrev;
}
else
{
// link the next to the prev (bypassing this one)
pRealPos->m_pNext->m_pPrev = pRealPos->m_pPrev;
}
LocalFree( pRealPos );
VALIDATELIST();
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CLISTPOS CList<NODETYPE>::FindIndex( int iIndex )
{
ASSERT( iIndex >= 0 );
CNode * pCur = m_pHead;
while ( iIndex > 0 && pCur != NULL )
{
pCur = pCur->m_pNext;
iIndex --;
}
return (CLISTPOS)(iIndex == 0 ? pCur : NULL );
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
void CList<NODETYPE>::RemoveAll( void )
{
// note we will not free the data elements, the client must do this...
CNode * pCur = m_pHead;
while (pCur != NULL )
{
CNode * pTmp = pCur->m_pNext;
LocalFree( pCur );
pCur = pTmp;
}
m_pHead = m_pTail = NULL;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CLISTPOS CList<NODETYPE>::AddTail( NODETYPE * pData )
{
CNode * pCurTail = m_pTail;
CNode * pNewNode = (CNode * ) LocalAlloc( GPTR, sizeof( CNode ));
if ( pNewNode == NULL )
{
return NULL;
}
pNewNode->m_pData = pData;
pNewNode->m_pPrev = pCurTail;
pNewNode->m_pNext = NULL;
m_pTail = pNewNode;
if ( pCurTail != NULL )
{
// we are not an empty list
pCurTail->m_pNext = pNewNode;
}
else
{
m_pHead = pNewNode;
}
VALIDATELIST();
return (CLISTPOS) pNewNode;
}
/////////////////////////////////////////////////////////////////////////////////////////
template< class NODETYPE >
CLISTPOS CList<NODETYPE>::AddBefore( CLISTPOS pPos, NODETYPE * pData )
{
if ( !pPos )
{
return NULL;
}
CNode * pPrev = (CNode *) pPos;
CNode * pNewNode = (CNode * ) LocalAlloc( GPTR, sizeof( CNode ));
if ( pNewNode == NULL )
{
return NULL;
}
pNewNode->m_pData = pData;
pNewNode->m_pPrev = pPrev->m_pPrev;
pNewNode->m_pNext = pPrev;
if ( pPrev->m_pPrev != NULL )
{
pPrev->m_pPrev->m_pNext = pNewNode;
}
else
{
// must be at the start of the list...
m_pHead = pNewNode;
}
pPrev->m_pPrev = pNewNode;
VALIDATELIST();
return (CLISTPOS) pNewNode;
}
/////////////////////////////////////////////////////////////////////////////////////////
#ifdef DEBUG
template< class NODETYPE >
void CList<NODETYPE>::ValidateList( )
{
CNode * pPos = m_pHead;
while ( pPos )
{
ASSERT( pPos->m_pData );
if ( pPos != m_pHead )
{
ASSERT( pPos->m_pPrev );
}
pPos = pPos->m_pNext;
}
pPos = m_pTail;
while ( pPos )
{
ASSERT( pPos->m_pData );
if ( pPos != m_pTail )
{
ASSERT( pPos->m_pNext );
}
pPos = pPos->m_pPrev;
}
if ( m_pHead || m_pTail )
{
ASSERT( !m_pHead->m_pPrev );
ASSERT( m_pTail );
ASSERT( m_pHead );
ASSERT( !m_pTail->m_pNext );
}
}
#endif
#endif