#ifndef __CIRCULARLIST_H__ #define __CIRCULARLIST_H__ // ************ WARNING: PRE-EMPTED BY (NOW IN) LIST.H ********************** /* #include "datalibx.h" #include "list.h" #define CLINKBUFFER ////////////////////////////////////////////////////////////////////////////// // CCircularList Class // template class CCircularListIter; template class CCircularList { public: friend class CCircularListIter; public: CCircularList(); ~CCircularList(); BOOL Init(); protected: VOID Uninit(); inline BOOL Initialized() const; inline BOOL Valid() const; public: // Insertion Functions TPData Insert(TPData pData, TKey key); TPData InsertForward(TPData pData, TKey key); TPData InsertBackward(TPData pData, TKey key); TPData InsertFirst(TPData pData, TKey key); TPData InsertLast(TPData pData, TKey key); // Deletion Functions TPData Remove(TKey key); TPData RemoveForward(TKey key); TPData RemoveBackward(TKey key); TPData RemoveFirst(TKey *pTKey = NULL); TPData RemoveLast(TKey *pTKey = NULL); VOID RemoveAll(); // Look up Functions TPData Peek(TKey key) const; TPData PeekForward(TKey key) const; TPData PeekBackward(TKey key) const; TPData PeekFirst(TKey *pTKey = NULL) const; TPData PeekLast(TKey *pTKey = NULL) const; // Display Functions VOID Display(); //Inlined Functions public: UINT_32 GetLength(); protected: // CLink Allocation CLink *AllocateLink(); VOID FreeLink(CLink *pCLink); // Insertion and Deletion VOID InsertNext(CLink *pCurr, CLink *pCLink); CLink *RemoveNext(CLink *pCurr); VOID InsertPrev(CLink *pCurr, CLink *pCLink); CLink *RemovePrev(CLink *pCurr); protected: CLink *m_pHead; CLink *m_pTail; // This is the same Sentinal Node as the Head UINT_32 m_uiAllocations; UINT_32 m_uiLength; #ifdef CLINKBUFFER CLink *m_pFree; CLinkBuffer *m_pCLinkBuffer; #endif // CLINKBUFFER }; ////////////////////////////////////////////////// // Inlined Functions // template inline BOOL CCircularList::Initialized() const { return (m_pHead != NULL) && (m_pTail != NULL) && (m_uiLength >= 1) && (m_uiAllocations >= 1); } template inline BOOL CCircularList::Valid() const { return Initialized() && (m_pHead == m_pTail) && (m_uiAllocations == m_uiLength); } template inline TPData CCircularList::Insert(TPData pData, TKey key) { return InsertForward(pData, key); } template inline TPData CCircularList::Remove(TKey key) { return RemoveForward(key); } template inline TPData CCircularList::Peek(TKey key) const { return PeekForward(key); } template inline UINT_32 CCircularList::GetLength() { return m_uiLength - 1; } ////////////////////////////////////////////////////////////////////////////// // CCircularListIter Class // template class CCircularListIter { public: CCircularListIter(); ~CCircularListIter(); BOOL Init(CCircularList *pCCircularList); protected: VOID Uninit(); BOOL Valid(); public: // Iteration Functions TPData Peek(TKey key); TPData PeekForward(TKey key); TPData PeekBackward(TKey key); TPData PeekFirst(TKey *pTKey = NULL); TPData PeekNext(TKey *pTKey = NULL); TPData PeekLast(TKey *pTKey = NULL); TPData PeekPrev(TKey *pTKey = NULL); protected: CCircularList *m_pCCircularList; CLink *m_pCurr; }; ////////////////////////////////////////////////// // Inlined Functions // template inline TPData CCircularListIter::Peek(TKey key) { return PeekForward(key); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // Class Implementations // ////////////////////////////////////////////////////////////////////////////// // CCircularList Class // template CCircularList::CCircularList() { m_pHead = NULL; m_pTail = NULL; m_uiAllocations = 0; m_uiLength = 0; #ifdef CLINKBUFFER m_pFree = NULL; m_pCLinkBuffer = NULL; #endif CLINKBUFFER } template CCircularList::~CCircularList() { Uninit(); } template BOOL CCircularList::Init() { ASSERT( m_pHead == NULL && m_pTail == NULL && m_uiLength == 0 ); m_pHead = AllocateLink(); ASSERT( m_pHead != NULL ); m_pHead->SetNext(m_pHead); m_pHead->SetPrev(m_pHead); m_pTail = m_pHead; m_uiLength = 1; ASSERT( Valid() ); return TRUE; } template VOID CCircularList::Uninit() { if ( m_pHead != NULL ) { RemoveAll(); ASSERT( m_pHead != NULL && m_pHead == m_pTail && m_uiLength == 1 ); m_uiLength = 0; FreeLink(m_pHead); ASSERT( m_uiAllocations == 0 ); } m_pHead = NULL; m_pTail = NULL; m_uiAllocations = 0; m_uiLength = 0; #ifdef CLINKBUFFER while ( m_pCLinkBuffer != NULL ) { CLinkBuffer *pCLinkBuffer; pCLinkBuffer = m_pCLinkBuffer; m_pCLinkBuffer = m_pCLinkBuffer->GetNext(); delete pCLinkBuffer; } m_pFree = NULL; #endif // CLINKBUFFER } template TPData CCircularList::InsertForward(TPData pData, TKey key) { ASSERT( Valid() ); CLink *pCurr; CLink *pCLink; // Allocate and Initialize a CLink pCLink = AllocateLink(); ASSERT( pCLink != NULL ); pCLink->Init(key, pData); // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pHead; pCurr->GetNext() != m_pTail; pCurr = pCurr->GetNext() ) { if ( pCurr->GetNext()->GetKey() > key ) { break; } } // Insert the CLink at the current position in the CCircularList InsertNext(pCurr, pCLink); return pData; } template TPData CCircularList::InsertBackward(TPData pData, TKey key) { ASSERT( Valid() ); CLink *pCurr; CLink *pCLink; // Allocate and Initialize a CLink pCLink = AllocateLink(); ASSERT( pCLink != NULL ); pCLink->Init(key, pData); // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pTail; pCurr->GetPrev() != m_pHead; pCurr = pCurr->GetPrev() ) { if ( pCurr->GetPrev()->GetKey() < key ) { break; } } // Insert the CLink at the current position in the CCircularList InsertPrev(pCurr, pCLink); return pData; } template TPData CCircularList::InsertFirst(TPData pData, TKey key) { ASSERT( Valid() ); CLink *pCLink; // Allocate and Initialize a CLink pCLink = AllocateLink(); ASSERT( pCLink != NULL ); pCLink->Init(key, pData); // Insert the CLink at the beginning of the CCircularList InsertNext(m_pHead, pCLink); return pData; } template TPData CCircularList::InsertLast(TPData pData, TKey key) { ASSERT( Valid() ); CLink *pCLink; // Allocate and Initialize a CLink pCLink = AllocateLink(); ASSERT( pCLink != NULL ); pCLink->Init(key, pData); // Insert the CLink at the end of the CCircularList InsertPrev(m_pTail, pCLink); return pData; } template TPData CCircularList::RemoveForward(TKey key) { ASSERT( Valid() ); CLink *pCurr; CLink *pCLink; TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pHead; pCurr->GetNext() != m_pTail; pCurr = pCurr->GetNext() ) { if ( pCurr->GetNext()->GetKey() < key ) { // Not there yet continue; } else if ( pCurr->GetNext()->GetKey() == key ) { // We found it // Remove this next CLink pCLink = RemoveNext(pCurr); ASSERT( pCLink != NULL ); // Pull out the Data from the CLink pData = pCLink->GetData(NULL); // Deallocate the CLink FreeLink(pCLink); break; } else { // We passed it break; } } return pData; } template TPData CCircularList::RemoveBackward(TKey key) { ASSERT( Valid() ); CLink *pCurr; CLink *pCLink; TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pTail; pCurr->GetPrev() != m_pHead; pCurr = pCurr->GetPrev() ) { if ( pCurr->GetPrev()->GetKey() > key ) { // Not there yet continue; } else if ( pCurr->GetPrev()->GetKey() == key ) { // We found it // Remove this prev CLink pCLink = RemovePrev(pCurr); ASSERT( pCLink != NULL ); // Pull out the Data from the CLink pData = pCLink->GetData(NULL); // Deallocate the CLink FreeLink(pCLink); break; } else { // We passed it break; } } return pData; } template TPData CCircularList::RemoveFirst(TKey *pTKey/* = NULL*//*) { ASSERT( Valid() ); CLink *pCLink; TPData pData; // Remove the CLink at the beginning of the CCircularList pCLink = RemoveNext(m_pHead); if ( pCLink == NULL ) { return NULL; } // Pull out the Data from the CLink pData = pCLink->GetData(pTKey); // Deallocate the CLink FreeLink(pCLink); return pData; } template TPData CCircularList::RemoveLast(TKey *pTKey/* = NULL*//*) { ASSERT( Valid() ); CLink *pCLink; TPData pData; // Remove the CLink at the end of the CCircularList pCLink = RemovePrev(m_pTail); if ( pCLink == NULL ) { return NULL; } // Pull out the Data from the CLink pData = pCLink->GetData(pTKey); // Deallocate the CLink FreeLink(pCLink); return pData; } template VOID CCircularList::RemoveAll() { ASSERT( Valid() ); CLink *pCLink; pCLink = RemoveNext(m_pHead); while ( pCLink != NULL ) { FreeLink(pCLink); pCLink = RemoveNext(m_pHead); } } template TPData CCircularList::PeekForward(TKey key) const { ASSERT( Valid() ); CLink *pCurr; TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pHead->GetNext(); pCurr != m_pTail; pCurr = pCurr->GetNext() ) { if ( pCurr->GetKey() < key ) { // Not there yet continue; } else if ( pCurr->GetKey() == key ) { // We found it // Pull out the Data from the CLink pData = pCurr->GetData(NULL); break; } else { // We passed it break; } } return pData; } template TPData CCircularList::PeekBackward(TKey key) const { ASSERT( Valid() ); CLink *pCurr; TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( pCurr = m_pTail->GetPrev(); pCurr != m_pHead; pCurr = pCurr->GetPrev() ) { if ( pCurr->GetKey() > key ) { // Not there yet continue; } else if ( pCurr->GetKey() == key ) { // We found it // Pull out the Data from the CLink pData = pCurr->GetData(NULL); break; } else { // We passed it break; } } return pData; } template TPData CCircularList::PeekFirst(TKey *pTKey/* = NULL */) const { CLink *pCurr; ASSERT( Valid() ); pCurr = m_pHead->GetNext(); if ( pCurr == m_pTail ) { pCurr = NULL; return NULL; } return pCurr->GetData(pTKey); } template TPData CCircularList::PeekLast(TKey *pTKey/* = NULL *//*) const { CLink *pCurr; ASSERT( Valid() ); pCurr = m_pTail->GetPrev(); if ( pCurr == m_pHead ) { pCurr = NULL; return NULL; } return pCurr->GetData(pTKey); } template VOID CCircularList::Display() { ASSERT( Valid() ); CLink *pCurr; for ( pCurr = m_pHead; pCurr->GetNext() != m_pTail; pCurr = pCurr->GetNext() ) { if ( pCurr == m_pHead ) { printf("(HEAD)->"); } pCurr->GetNext()->Display(); printf("->"); if ( m_pTail == pCurr->GetNext() ) { printf("<-(TAIL)"); } } printf("\n"); } #ifdef CLINKBUFFER template CLink *CCircularList::AllocateLink() { CLink *pCLink; ASSERT( m_uiAllocations == m_uiLength ); if ( m_pFree == NULL ) { //printf("*** Allocating a new link Buffer ***\n"); // The free list is empty so // dynamically allocate a new buffer CLinkBuffer *pCLinkBuffer; pCLinkBuffer = new CLinkBuffer; ASSERT( pCLinkBuffer != NULL ); pCLinkBuffer->Init(); // Insert the new buffer at the beginning of the buffer list // so that we can deallocate it later pCLinkBuffer->SetNext(m_pCLinkBuffer); m_pCLinkBuffer = pCLinkBuffer; // Set the free list to be the list contained in the buffer m_pFree = m_pCLinkBuffer->GetBuffer(); ASSERT( m_pFree != NULL ); } ASSERT( m_pFree != NULL ); // Take the first free link off the free list pCLink = m_pFree; m_pFree = m_pFree->GetNext(); pCLink->SetNext(NULL); m_uiAllocations++; return pCLink; } template VOID CCircularList::FreeLink(CLink *pCLink) { ASSERT( pCLink != NULL ); // Insert the newly freed link at the beginning of the free list to be reused pCLink->SetNext(m_pFree); m_pFree = pCLink; m_uiAllocations--; ASSERT( m_uiAllocations == m_uiLength ); } #else // CLINKBUFFER template CLink *CCircularList::AllocateLink() { CLink *pCLink; ASSERT( Valid() ); pCLink = new CLink; ASSERT( pCLink != NULL ); m_uiAllocations++; return pCLink; } template VOID CCircularList::FreeLink(CLink *pCLink) { ASSERT( Initialized() ); ASSERT( pCLink != NULL ); delete pCLink; m_uiAllocations--; ASSERT( Valid() ); } #endif // CLINKBUFFER template VOID CCircularList::InsertNext(CLink *pCurr, CLink *pCLink) { ASSERT( Initialized() ); ASSERT( pCurr != NULL && pCLink != NULL ); if ((pCurr == m_pHead) && (m_uiLength == 1)) { pCLink->SetNext(pCLink); pCLink->SetPrev(pCLink); } else if (pCurr == m_pHead) { pCLink->SetNext(pCurr->GetNext()); pCLink->SetPrev(pCurr->GetPrev()); pCurr->GetPrev()->SetNext(pCLink); } else { pCLink->SetNext(pCurr->GetNext()); pCLink->SetPrev(pCurr); } pCurr->GetNext()->SetPrev(pCLink); pCurr->SetNext(pCLink); m_uiLength++; ASSERT( Valid() ); } template CLink *CCircularList::RemoveNext(CLink *pCurr) { ASSERT( Valid() ); ASSERT( pCurr != NULL ); CLink *pCLink; pCLink = pCurr->GetNext(); // list is empty if ( pCLink == m_pTail ) { return NULL; } // only one elt in list else if ( pCLink == pCLink->GetPrev() ) { m_pTail->SetNext(m_pTail); m_pTail->SetPrev(m_pTail); } // Removing first elt in list else if ( pCurr == m_pTail) { pCurr->SetNext(pCLink->GetNext()); pCurr->GetNext()->SetPrev(pCLink->GetPrev()); pCLink->GetPrev()->SetNext(pCLink->GetNext()); } else { pCurr->SetNext(pCLink->GetNext()); pCurr->GetNext()->SetPrev(pCurr); } m_uiLength--; return pCLink; } template VOID CCircularList::InsertPrev(CLink *pCurr, CLink *pCLink) { ASSERT( Initialized() ); ASSERT( pCurr != NULL && pCLink != NULL ); if ((pCurr == m_pTail) && (m_uiLength == 1)) { pCLink->SetNext(pCLink); pCLink->SetPrev(pCLink); } else if (pCurr == m_pHead) { pCLink->SetNext(pCurr->GetNext()); pCLink->SetPrev(pCurr->GetPrev()); pCurr->GetNext()->SetPrev(pCLink); } else { pCLink->SetPrev(pCurr->GetPrev()); pCLink->SetNext(pCurr); } pCurr->GetPrev()->SetNext(pCLink); pCurr->SetPrev(pCLink); m_uiLength++; ASSERT( Valid() ); } template CLink *CCircularList::RemovePrev(CLink *pCurr) { ASSERT( Valid() ); ASSERT( pCurr != NULL ); CLink *pCLink; pCLink = pCurr->GetPrev(); // list is empty if ( pCLink == m_pTail ) { return NULL; } // only one elt in list else if ( pCLink == pCLink->GetPrev()) { m_pTail->SetNext(m_pTail); m_pTail->SetPrev(m_pTail); } // Removing last elt in list else if ( pCurr == m_pTail) { pCurr->SetPrev(pCLink->GetPrev()); pCurr->GetPrev()->SetNext(pCLink->GetNext()); pCLink->GetNext()->SetPrev(pCLink->GetPrev()); } else { pCurr->SetPrev(pCLink->GetPrev()); pCurr->GetPrev()->SetNext(pCurr); } m_uiLength--; return pCLink; } ////////////////////////////////////////////////////////////////////////////// // CCircularListIter Class // template CCircularListIter::CCircularListIter() { m_pCCircularList = NULL; m_pCurr = NULL; } template CCircularListIter::~CCircularListIter() { Uninit(); } BOOL CCircularListIter::Init(CCircularList *pCCircularList) { ASSERT( pCCircularList != NULL ); Uninit(); m_pCCircularList = pCCircularList; m_pCurr = NULL; return TRUE; } template VOID CCircularListIter::Uninit() { m_pCCircularList = NULL; m_pCurr = NULL; } template BOOL CCircularListIter::Foo() { return (m_pCCircularList != NULL); } template VOID CCircularListIter::SetCurr(CLink *pCurr) { m_pCurr = pCurr; // m_pCurr = (CLink *)pCurr; } template BOOL CCircularListIter::Valid() { return (m_pCCircularList != NULL); } template TPData CCircularListIter::PeekForward(TKey key) { ASSERT( Valid() ); TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( m_pCurr = m_pCCircularList->m_pHead->GetNext(); m_pCurr != m_pCCircularList->m_pTail; m_pCurr = m_pCurr->GetNext() ) { if ( m_pCurr->GetKey() < key ) { // Not there yet continue; } else if ( m_pCurr->GetKey() == key ) { // We found it // Pull out the Data from the CLink pData = m_pCurr->GetData(NULL); break; } else { // We passed it break; } } return pData; } template TPData CCircularListIter::PeekBackward(TKey key) { ASSERT( Valid() ); TPData pData; pData = NULL; // Find the correct position in the CCircularList for the CLink for ( m_pCurr = m_pCCircularList->m_pTail->GetPrev(); m_pCurr != m_pCCircularList->m_pHead; m_pCurr = m_pCurr->GetPrev() ) { if ( m_pCurr->GetKey() > key ) { // Not there yet continue; } else if ( m_pCurr->GetKey() == key ) { // We found it // Pull out the Data from the CLink pData = m_pCurr->GetData(NULL); break; } else { // We passed it break; } } return pData; } template TPData CCircularListIter::PeekFirst(TKey *pTKey/* = NULL *//*) { ASSERT( Valid() ); m_pCurr = m_pCCircularList->m_pHead->GetNext(); if ( m_pCurr == m_pCCircularList->m_pTail ) { m_pCurr = NULL; return NULL; } return m_pCurr->GetData(pTKey); } template TPData CCircularListIter::PeekNext(TKey *pTKey/* = NULL*//*) { ASSERT( Valid() ); if ( m_pCurr == NULL ) { return NULL; } m_pCurr = m_pCurr->GetNext(); return m_pCurr->GetData(pTKey); } template TPData CCircularListIter::PeekLast(TKey *pTKey/* = NULL *//*) { ASSERT( Valid() ); m_pCurr = m_pCCircularList->m_pTail->GetPrev(); if ( m_pCurr == m_pCCircularList->m_pHead ) { m_pCurr = NULL; return NULL; } return m_pCurr->GetData(pTKey); } template TPData CCircularListIter::PeekPrev(TKey *pTKey/* = NULL*//*) { ASSERT( Valid() ); if ( m_pCurr == NULL ) { return NULL; } m_pCurr = m_pCurr->GetPrev(); return m_pCurr->GetData(pTKey); } */ #endif // __CIRCULARLIST_H__