You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

784 lines
16 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//////////////////////////////////////////////////////////////////////////////
//文件 TObjectList.h
//主要功能:
// 指针链表模块类
#pragma once
namespace NSet
{
#ifndef _WIN64
typedef long DF_LONG; //定义32位整型
#else
typedef __int64 DF_LONG; //定义64位整型
#endif
template <class T>
class TObjectList
{
public:
// Construction
TObjectList(int nBlockSize = 20);
TObjectList(TObjectList<T>& pNewList, int nBlockSize = 20);
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<T>* pNewList);
void AddTail(TObjectList<T>* 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)
long GetIndex(POSITION pos, bool bFaster = false); //bFaster=true时必须在使用ResetIndex后
//reset the every element's index
void ResetIndex(void);
// Implementation
protected:
struct TNode
{
TNode * pNext;
TNode * pPrev;
T * data;
long nIndex; //当前节点的索引号必须在使用ResetIndex后才正确
};
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);
void AddTail(TNode*);
void AddHead(TNode*);
public:
// local typedefs for class templates
typedef T* BASE_TYPE;
typedef T* BASE_ARG_TYPE;
};
//类实现
template <class T>
TObjectList<T>::TObjectList(int nBlockSize /*= 20*/)
{
m_nBlockSize = nBlockSize;
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks = NULL;
}
template <class T>
TObjectList<T>::TObjectList(TObjectList<T>& pNewList, int nBlockSize /*= 20*/)
{
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 <class T>
TObjectList<T>::~TObjectList()
{
RemoveAll();
}
template <class T>
DF_LONG TObjectList<T>::GetCount() const
{
return m_nCount;
}
template <class T>
DF_LONG TObjectList<T>::GetSize() const
{
return m_nCount;
}
template <class T>
bool TObjectList<T>::IsEmpty() const
{
return m_nCount == 0;
}
template <class T>
T*& TObjectList<T>::GetHead()
{
//ENSURE(m_pNodeHead != NULL);
return m_pNodeHead->data;
}
template <class T>
const T* TObjectList<T>::GetHead() const
{
//ENSURE(m_pNodeHead != NULL);
if(m_pNodeHead == NULL)
return NULL;
return m_pNodeHead->data;
}
template <class T>
T*& TObjectList<T>::GetTail()
{
//ENSURE(m_pNodeTail != NULL);
return m_pNodeTail->data;
}
template <class T>
const T* TObjectList<T>::GetTail() const
{
//ENSURE(m_pNodeTail != NULL);
if(m_pNodeTail == NULL)
return NULL;
return m_pNodeTail->data;
}
template <class T>
T* TObjectList<T>::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 <class T>
T* TObjectList<T>::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 <class T>
void TObjectList<T>::AddHead(TNode* pNewNode)
{
if(pNewNode == m_pNodeHead)
return;
if (m_pNodeHead != NULL)
m_pNodeHead->pPrev = pNewNode;
else
m_pNodeTail = pNewNode;
m_pNodeHead = pNewNode;
}
template <class T>
POSITION TObjectList<T>::AddHead(T* newElement)
{
TNode* pNewNode = NewNode(NULL, m_pNodeHead);
pNewNode->data = newElement;
AddHead(pNewNode);
return (POSITION) pNewNode;
}
template <class T>
POSITION TObjectList<T>::AddTail(T* newElement)
{
TNode* pNewNode = NewNode(m_pNodeTail, NULL);
pNewNode->data = newElement;
AddTail(pNewNode);
return (POSITION) pNewNode;
}
template <class T>
void TObjectList<T>::AddTail(TNode* pNewNode)
{
if(pNewNode == m_pNodeTail)
return;
if (m_pNodeTail != NULL)
m_pNodeTail->pNext = pNewNode;
else
m_pNodeHead = pNewNode;
m_pNodeTail = pNewNode;
}
template <class T>
void TObjectList<T>::AddHead(TObjectList<T>* 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 <class T>
void TObjectList<T>::AddTail(TObjectList<T>* pNewList)
{
ENSURE(pNewList != NULL);
// add a list of same elements
POSITION pos = pNewList->GetHeadPosition();
while (pos != NULL)
AddTail(pNewList->GetNext(pos));
}
template <class T>
void TObjectList<T>::RemoveAll()
{
m_pBlocks->FreeDataChain();
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks = NULL;
}
template <class T>
void TObjectList<T>::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 <class T>
bool TObjectList<T>::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 <class T>
POSITION TObjectList<T>::GetHeadPosition() const
{
return (POSITION) m_pNodeHead;
}
template <class T>
POSITION TObjectList<T>::GetTailPosition() const
{
return (POSITION) m_pNodeTail;
}
template <class T>
T*& TObjectList<T>::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 <class T>
const T* TObjectList<T>::GetNext(POSITION& rPosition) const // return *Position++
{
TNode* pNode = (TNode*) rPosition;
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
//if( pNode == NULL )
// AfxThrowInvalidArgException();
if(0 == pNode)
return 0;
rPosition = (POSITION) pNode->pNext;
return pNode->data;
}
template <class T>
T*& TObjectList<T>::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 <class T>
const T* TObjectList<T>::GetPrev(POSITION& rPosition) const // return *Position--
{
TNode* pNode = (TNode*) rPosition;
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
//if( pNode == NULL )
// AfxThrowInvalidArgException();
if(0 == pNode)
return 0;
rPosition = (POSITION) pNode->pPrev;
return pNode->data;
}
template <class T>
T*& TObjectList<T>::GetAt(POSITION position)
{
TNode* pNode = (TNode*) position;
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
//if( pNode == NULL )
// AfxThrowInvalidArgException();
return pNode->data;
}
template <class T>
const T* TObjectList<T>::GetAt(POSITION position) const
{
TNode* pNode = (TNode*) position;
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
//if( pNode == NULL )
// AfxThrowInvalidArgException();
if(0 == pNode)
return 0;
return pNode->data;
}
template <class T>
void TObjectList<T>::SetAt(POSITION pos, T* newElement)
{
TNode* pNode = (TNode*) pos;
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
//if( pNode == NULL )
// AfxThrowInvalidArgException();
if(0 == pNode)
return;
pNode->data = newElement;
}
template <class T>
void TObjectList<T>::MoveToBefore(POSITION pos, POSITION posMove)
{
RemoveAtNoClear(posMove); //先移除元素
TNode* pOldNode = (TNode*) pos;
TNode* pMoveNode = (TNode*) posMove;
if(pOldNode == NULL)
{
pMoveNode->pPrev = NULL;
pMoveNode->pNext = m_pNodeHead;
AddHead(pMoveNode);
}
else
{
pMoveNode->pPrev = pOldNode->pPrev;
pMoveNode->pNext = pOldNode;
if (pOldNode->pPrev != NULL)
{
//#ifndef _GDF_QT
// ASSERT(AfxIsValidAddress(pOldNode->pPrev, sizeof(TNode)));
//#endif
pOldNode->pPrev->pNext = pMoveNode;
}
else
{
ASSERT(pOldNode == m_pNodeHead);
m_pNodeHead = pMoveNode;
}
pOldNode->pPrev = pMoveNode;
}
}
template <class T>
void TObjectList<T>::MoveToAfter(POSITION pos, POSITION posMove)
{
RemoveAtNoClear(posMove); //先移除元素
TNode* pOldNode = (TNode*) pos;
TNode* pMoveNode = (TNode*) posMove;
if(pOldNode == NULL)
{
pMoveNode->pPrev = m_pNodeTail;
pMoveNode->pNext = NULL;
AddTail(pMoveNode);
}
else
{
pMoveNode->pPrev = pOldNode;
pMoveNode->pNext = pOldNode->pNext;
if (pOldNode->pNext != NULL)
{
//#ifndef _GDF_QT
// ASSERT(AfxIsValidAddress(pOldNode->pNext, sizeof(TNode)));
//#endif
pOldNode->pNext->pPrev = pMoveNode;
}
else
{
ASSERT(pOldNode == m_pNodeTail);
m_pNodeTail = pMoveNode;
}
pOldNode->pNext = pMoveNode;
}
}
template <class T>
void TObjectList<T>::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(pOldNode->pPrev != NULL);
if(pOldNode->pPrev != NULL)
pOldNode->pPrev->pNext = pOldNode->pNext;
}
if (pOldNode == m_pNodeTail)
{
m_pNodeTail = pOldNode->pPrev;
}
else
{
ASSERT(pOldNode->pNext != NULL);
if(pOldNode->pNext != NULL)
pOldNode->pNext->pPrev = pOldNode->pPrev;
}
}
template <class T>
void TObjectList<T>::RemoveAt(POSITION position)
{
RemoveAtNoClear(position);
TNode* pOldNode = (TNode*) position;
FreeNode(pOldNode);
}
template <class T>
POSITION TObjectList<T>::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 <class T>
POSITION TObjectList<T>::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 <class T>
POSITION TObjectList<T>::Find(T* searchValue, POSITION startAfter /*= NULL*/) 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 <class T>
POSITION TObjectList<T>::FindIndex(INT_PTR nIndex) const
{
if (nIndex >= m_nCount || nIndex < 0)
return NULL; // went too far
TNode* pNode = NULL;
if(nIndex < m_nCount / 2)
{
pNode = m_pNodeHead;
while (nIndex--)
{
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
pNode = pNode->pNext;
}
}
else
{
//
nIndex = (m_nCount - 1) - nIndex;
pNode = m_pNodeTail;
while (nIndex--)
{
//ASSERT(AfxIsValidAddress(pNode, sizeof(TNode)));
pNode = pNode->pPrev;
}
}
return (POSITION) pNode;
}
template <class T>
void TObjectList<T>::ResetIndex(void)
{
long nCount = 0;
TNode* pNode = m_pNodeHead;
while(pNode != NULL)
{
pNode->nIndex = nCount++;
pNode = pNode->pNext;
}
}
template <class T>
long TObjectList<T>::GetIndex(POSITION pos, bool bFaster /*= false*/)
{
if(pos==NULL)
return -1;
TNode* pFindNode = (TNode*) pos;
if(bFaster)
return pFindNode->nIndex; //必须在使用ResetIndex后
long n = 0;
TNode* pNode = m_pNodeHead;
while(pNode != pFindNode)
{
n++;
pNode = pNode->pNext;
}
return n;
}
template <class T>
typename TObjectList<T>::TNode* TObjectList<T>::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 <class T>
void TObjectList<T>::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 //取消类型定义
typedef TObjectList<void> TPtrList; //指针链表
};
using namespace NSet;