290 lines
6.2 KiB
C
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
|