////////////////////////////////////////////////////////////////////////////// //文件 TObjectList.h //主要功能: // 指针链表模块类 ///////////////////////////////////////////////////////////////////////////// #ifndef _TOBJECTLIST_H #define _TOBJECTLIST_H #pragma once namespace NSet { #ifndef _WIN64 typedef long DF_LONG; //定义32位整型 #else typedef __int64 DF_LONG; //定义64位整型 #endif template class TObjectList { public: // Construction TObjectList(int nBlockSize = 10); TObjectList(TObjectList& pNewList, int nBlockSize = 10); virtual ~TObjectList(); // Attributes (head and tail) // count of elements DF_LONG GetCount() const; DF_LONG GetSize() const; bool IsEmpty() const; // peek at head or tail T*& GetHead(); const T* GetHead() const; T*& GetTail(); const T* GetTail() const; // Operations // get head or tail (and remove it) - don't call on empty list! T* RemoveHead(); T* RemoveTail(); // add before head or after tail POSITION AddHead(T* newElement); POSITION AddTail(T* newElement); // add another list of elements before head or after tail void AddHead(TObjectList* pNewList); void AddTail(TObjectList* pNewList); // remove all elements void RemoveAll(); void DeepErase(); //深度空间释放,包括指针指向的空间 // iteration POSITION GetHeadPosition() const; POSITION GetTailPosition() const; T*& GetNext(POSITION& rPosition); // return *Position++ const T* GetNext(POSITION& rPosition) const; // return *Position++ T*& GetPrev(POSITION& rPosition); // return *Position-- const T* GetPrev(POSITION& rPosition) const; // return *Position-- // getting/modifying an element at a given position T*& GetAt(POSITION position); const T* GetAt(POSITION position) const; void SetAt(POSITION pos, T* newElement); void RemoveAt(POSITION position); bool Swap(POSITION pos1, POSITION pos2); //swap two position element void MoveToBefore(POSITION pos, POSITION posMove); void MoveToAfter(POSITION pos, POSITION posMove); // inserting before or after a given position POSITION InsertBefore(POSITION position, T* newElement); POSITION InsertAfter(POSITION position, T* newElement); // helper functions (note: O(n) speed) POSITION Find(T* searchValue, POSITION startAfter = NULL) const; // defaults to starting at the HEAD // return NULL if not found POSITION FindIndex(INT_PTR nIndex) const; // get the 'nIndex'th element (may return NULL) // Implementation protected: struct TNode { TNode * pNext; TNode * pPrev; T * data; }; struct CBlock // warning variable length structure { CBlock* pNext; #ifndef _WIN64 #if (_AFX_PACKING >= 8) DWORD dwReserved[1]; // align on 8 byte boundary #endif #endif // BYTE data[maxNum*elementSize]; void* data() { return this+1; } static CBlock* Create(CBlock*& pHead, DF_LONG nMax, DF_LONG cbElement) { CBlock* p = (CBlock*) new BYTE[sizeof(CBlock) + nMax * cbElement]; // may throw exception p->pNext = (CBlock*)pHead; pHead = p; // change head (adds in reverse order for simplicity) return p; } // like 'calloc' but no zero fill // may throw memory exceptions void FreeDataChain() // free this one and links { CBlock* p = this; while (p != NULL) { BYTE* bytes = (BYTE*) p; CBlock* pNext = p->pNext; delete[] bytes; p = pNext; } } }; protected: TNode* m_pNodeHead; TNode* m_pNodeTail; TNode* m_pNodeFree; CBlock* m_pBlocks; DF_LONG m_nBlockSize; DF_LONG m_nCount; TNode* NewNode(TNode*, TNode*); void FreeNode(TNode*); void RemoveAtNoClear(POSITION position); public: // local typedefs for class templates typedef T* BASE_TYPE; typedef T* BASE_ARG_TYPE; }; //类实现 template TObjectList::TObjectList(int nBlockSize) { m_nBlockSize = nBlockSize; m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; } template TObjectList::TObjectList(TObjectList& pNewList, int nBlockSize) { m_nBlockSize = nBlockSize; m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; // add a list of same elements AddTail(&pNewList); } template TObjectList::~TObjectList() { RemoveAll(); } template DF_LONG TObjectList::GetCount() const { return m_nCount; } template DF_LONG TObjectList::GetSize() const { return m_nCount; } template bool TObjectList::IsEmpty() const { return m_nCount == 0; } template T*& TObjectList::GetHead() { ENSURE(m_pNodeHead != NULL); return m_pNodeHead->data; } template const T* TObjectList::GetHead() const { ENSURE(m_pNodeHead != NULL); if(m_pNodeHead == NULL) return NULL; return m_pNodeHead->data; } template T*& TObjectList::GetTail() { ENSURE(m_pNodeTail != NULL); return m_pNodeTail->data; } template const T* TObjectList::GetTail() const { ENSURE(m_pNodeTail != NULL); if(m_pNodeTail == NULL) return NULL; return m_pNodeTail->data; } template T* TObjectList::RemoveHead() { ENSURE(m_pNodeHead != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeHead, sizeof(TNode))); TNode* pOldNode = m_pNodeHead; T* returnValue = pOldNode->data; m_pNodeHead = pOldNode->pNext; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = NULL; else m_pNodeTail = NULL; FreeNode(pOldNode); return returnValue; } template T* TObjectList::RemoveTail() { ENSURE(m_pNodeTail != NULL); // don't call on empty list !!! ASSERT(AfxIsValidAddress(m_pNodeTail, sizeof(TNode))); TNode* pOldNode = m_pNodeTail; T* returnValue = pOldNode->data; m_pNodeTail = pOldNode->pPrev; if (m_pNodeTail != NULL) m_pNodeTail->pNext = NULL; else m_pNodeHead = NULL; FreeNode(pOldNode); return returnValue; } template POSITION TObjectList::AddHead(T* newElement) { TNode* pNewNode = NewNode(NULL, m_pNodeHead); pNewNode->data = newElement; if (m_pNodeHead != NULL) m_pNodeHead->pPrev = pNewNode; else m_pNodeTail = pNewNode; m_pNodeHead = pNewNode; return (POSITION) pNewNode; } template POSITION TObjectList::AddTail(T* newElement) { TNode* pNewNode = NewNode(m_pNodeTail, NULL); pNewNode->data = newElement; if (m_pNodeTail != NULL) m_pNodeTail->pNext = pNewNode; else m_pNodeHead = pNewNode; m_pNodeTail = pNewNode; return (POSITION) pNewNode; } template void TObjectList::AddHead(TObjectList* pNewList) { ENSURE(pNewList != NULL); // add a list of same elements to head (maintain order) POSITION pos = pNewList->GetTailPosition(); while (pos != NULL) AddHead(pNewList->GetPrev(pos)); } template void TObjectList::AddTail(TObjectList* pNewList) { ENSURE(pNewList != NULL); // add a list of same elements POSITION pos = pNewList->GetHeadPosition(); while (pos != NULL) AddTail(pNewList->GetNext(pos)); } template void TObjectList::RemoveAll() { m_pBlocks->FreeDataChain(); m_nCount = 0; m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL; m_pBlocks = NULL; } template void TObjectList::DeepErase() { TNode* pNode = m_pNodeHead; while(pNode != NULL) { TNode* pNext = pNode->pNext; delete pNode->data; //delete pNode; pNode = pNext; } m_nCount = 0; m_pNodeHead = m_pNodeTail = NULL; } //swap two position element template bool TObjectList::Swap(POSITION pos1, POSITION pos2) { if(pos1==pos2 || pos1==NULL || pos2==NULL) return false; TNode* pNode1 = (TNode*) pos1; TNode* pNode2 = (TNode*) pos2; T* pTempData = pNode1->data; pNode1->data = pNode2->data; pNode2->data = pTempData; /*TNode* pTemp; pTemp = pNode1->pPrev; pNode1->pPrev = pNode2->pPrev; pNode2->pPrev = pTemp; pTemp = pNode1->pNext; pNode1->pNext = pNode2->pNext; pNode2->pNext = pTemp; if(pNode1->pPrev == pNode1) pNode1->pPrev = pNode2; if(pNode1->pNext == pNode1) pNode1->pNext = pNode2; if(pNode2->pPrev == pNode2) pNode2->pPrev = pNode1; if(pNode2->pNext == pNode2) pNode2->pNext = pNode1;*/ return true; } template POSITION TObjectList::GetHeadPosition() const { return (POSITION) m_pNodeHead; } template POSITION TObjectList::GetTailPosition() const { return (POSITION) m_pNodeTail; } template T*& TObjectList::GetNext(POSITION& rPosition) // return *Position++ { TNode* pNode = (TNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); rPosition = (POSITION) pNode->pNext; return pNode->data; } template const T* TObjectList::GetNext(POSITION& rPosition) const // return *Position++ { TNode* pNode = (TNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); rPosition = (POSITION) pNode->pNext; return pNode->data; } template T*& TObjectList::GetPrev(POSITION& rPosition) // return *Position-- { TNode* pNode = (TNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); rPosition = (POSITION) pNode->pPrev; return pNode->data; } template const T* TObjectList::GetPrev(POSITION& rPosition) const // return *Position-- { TNode* pNode = (TNode*) rPosition; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); rPosition = (POSITION) pNode->pPrev; return pNode->data; } template T*& TObjectList::GetAt(POSITION position) { TNode* pNode = (TNode*) position; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); return pNode->data; } template const T* TObjectList::GetAt(POSITION position) const { TNode* pNode = (TNode*) position; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); return pNode->data; } template void TObjectList::SetAt(POSITION pos, T* newElement) { TNode* pNode = (TNode*) pos; ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); if( pNode == NULL ) AfxThrowInvalidArgException(); pNode->data = newElement; } template void TObjectList::MoveToBefore(POSITION pos, POSITION posMove) { RemoveAtNoClear(posMove); //先移除元素 TNode* pOldNode = (TNode*) pos; TNode* pMoveNode = (TNode*) posMove; pMoveNode->pPrev = pOldNode->pPrev; pMoveNode->pNext = pOldNode; if (pOldNode->pPrev != NULL) { ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode))); pOldNode->pPrev->pNext = pMoveNode; } else { ASSERT(pOldNode == m_pNodeHead); m_pNodeHead = pMoveNode; } pOldNode->pPrev = pMoveNode; } template void TObjectList::MoveToAfter(POSITION pos, POSITION posMove) { RemoveAtNoClear(posMove); //先移除元素 TNode* pOldNode = (TNode*) pos; TNode* pMoveNode = (TNode*) posMove; pMoveNode->pPrev = pOldNode; pMoveNode->pNext = pOldNode->pNext; if (pOldNode->pNext != NULL) { ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode))); pOldNode->pNext->pPrev = pMoveNode; } else { ASSERT(pOldNode == m_pNodeTail); m_pNodeTail = pMoveNode; } pOldNode->pNext = pMoveNode; } template void TObjectList::RemoveAtNoClear(POSITION position) { TNode* pOldNode = (TNode*) position; ASSERT(AfxIsValidAddress(pOldNode, sizeof(TNode))); // remove pOldNode from list if (pOldNode == m_pNodeHead) { m_pNodeHead = pOldNode->pNext; } else { ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode))); pOldNode->pPrev->pNext = pOldNode->pNext; } if (pOldNode == m_pNodeTail) { m_pNodeTail = pOldNode->pPrev; } else { ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode))); pOldNode->pNext->pPrev = pOldNode->pPrev; } } template void TObjectList::RemoveAt(POSITION position) { RemoveAtNoClear(position); TNode* pOldNode = (TNode*) position; FreeNode(pOldNode); } template POSITION TObjectList::InsertBefore(POSITION position, T* newElement) { if (position == NULL) return AddHead(newElement); // insert before nothing -> head of the list // Insert it before position TNode* pOldNode = (TNode*) position; TNode* pNewNode = NewNode(pOldNode->pPrev, pOldNode); pNewNode->data = newElement; if (pOldNode->pPrev != NULL) { ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode))); pOldNode->pPrev->pNext = pNewNode; } else { ASSERT(pOldNode == m_pNodeHead); m_pNodeHead = pNewNode; } pOldNode->pPrev = pNewNode; return (POSITION) pNewNode; } template POSITION TObjectList::InsertAfter(POSITION position, T* newElement) { if (position == NULL) return AddTail(newElement); // insert after nothing -> tail of the list // Insert it before position TNode* pOldNode = (TNode*) position; ASSERT(AfxIsValidAddress(pOldNode, sizeof(TNode))); TNode* pNewNode = NewNode(pOldNode, pOldNode->pNext); pNewNode->data = newElement; if (pOldNode->pNext != NULL) { ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode))); pOldNode->pNext->pPrev = pNewNode; } else { ASSERT(pOldNode == m_pNodeTail); m_pNodeTail = pNewNode; } pOldNode->pNext = pNewNode; return (POSITION) pNewNode; } template POSITION TObjectList::Find(T* searchValue, POSITION startAfter ) const { TNode* pNode = (TNode*) startAfter; if (pNode == NULL) { pNode = m_pNodeHead; // start at head } else { ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); pNode = pNode->pNext; // start after the one specified } for (; pNode != NULL; pNode = pNode->pNext) if (pNode->data == searchValue) return (POSITION)pNode; return NULL; } template POSITION TObjectList::FindIndex(INT_PTR nIndex) const { if (nIndex >= m_nCount || nIndex < 0) return NULL; // went too far TNode* pNode = m_pNodeHead; while (nIndex--) { ASSERT(AfxIsValidAddress(pNode, sizeof(TNode))); pNode = pNode->pNext; } return (POSITION) pNode; } template typename TObjectList::TNode* TObjectList::NewNode(TNode*pPrev , TNode* pNext) { if (m_pNodeFree == NULL) { if(m_nBlockSize<=0) m_nBlockSize = 10; CBlock* pNewBlock = CBlock::Create(m_pBlocks, m_nBlockSize, sizeof(TNode)); // chain them into free list TNode* pNode = (TNode*) pNewBlock->data(); pNode += m_nBlockSize - 1; for(DF_LONG i=m_nBlockSize-1; i>=0; i--,pNode--) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; } } TNode *pNode = m_pNodeFree; m_pNodeFree = m_pNodeFree->pNext; pNode->pPrev = pPrev; pNode->pNext = pNext; pNode->data = NULL; m_nCount++; return pNode; } template void TObjectList::FreeNode(TNode* pNode) { pNode->pNext = m_pNodeFree; m_pNodeFree = pNode; m_nCount--; // if no more elements, cleanup completely if (m_nCount == 0) RemoveAll(); } #undef DF_LONG //取消类型定义 }; using namespace NSet; #endif