?? afxtempl.h
字號:
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
{
ASSERT_VALID(this);
ASSERT(nIndex >= 0);
if (nIndex >= m_nSize)
SetSize(nIndex+1, -1);
m_pData[nIndex] = newElement;
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount /*=1*/)
{
ASSERT_VALID(this);
ASSERT(nIndex >= 0); // will expand to meet need
ASSERT(nCount > 0); // zero or negative size not allowed
if (nIndex >= m_nSize)
{
// adding after the end of the array
SetSize(nIndex + nCount, -1); // grow so nIndex is valid
}
else
{
// inserting in the middle of the array
int nOldSize = m_nSize;
SetSize(m_nSize + nCount, -1); // grow it to new size
// destroy intial data before copying over it
DestructElements<TYPE>(&m_pData[nOldSize], nCount);
// shift old data up to fill gap
memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
(nOldSize-nIndex) * sizeof(TYPE));
// re-init slots we copied from
ConstructElements<TYPE>(&m_pData[nIndex], nCount);
}
// insert new value in the gap
ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::RemoveAt(int nIndex, int nCount)
{
ASSERT_VALID(this);
ASSERT(nIndex >= 0);
ASSERT(nCount >= 0);
ASSERT(nIndex + nCount <= m_nSize);
// just remove a range
int nMoveCount = m_nSize - (nIndex + nCount);
DestructElements<TYPE>(&m_pData[nIndex], nCount);
if (nMoveCount)
memmove(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(TYPE));
m_nSize -= nCount;
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::InsertAt(int nStartIndex, CArray* pNewArray)
{
ASSERT_VALID(this);
ASSERT(pNewArray != NULL);
ASSERT_VALID(pNewArray);
ASSERT(nStartIndex >= 0);
if (pNewArray->GetSize() > 0)
{
InsertAt(nStartIndex, pNewArray->GetAt(0), pNewArray->GetSize());
for (int i = 0; i < pNewArray->GetSize(); i++)
SetAt(nStartIndex + i, pNewArray->GetAt(i));
}
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::Serialize(CArchive& ar)
{
ASSERT_VALID(this);
CObject::Serialize(ar);
if (ar.IsStoring())
{
ar.WriteCount(m_nSize);
}
else
{
DWORD nOldSize = ar.ReadCount();
SetSize(nOldSize, -1);
}
SerializeElements<TYPE>(ar, m_pData, m_nSize);
}
#ifdef _DEBUG
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
dc << "with " << m_nSize << " elements";
if (dc.GetDepth() > 0)
{
dc << "\n";
DumpElements<TYPE>(dc, m_pData, m_nSize);
}
dc << "\n";
}
template<class TYPE, class ARG_TYPE>
void CArray<TYPE, ARG_TYPE>::AssertValid() const
{
CObject::AssertValid();
if (m_pData == NULL)
{
ASSERT(m_nSize == 0);
ASSERT(m_nMaxSize == 0);
}
else
{
ASSERT(m_nSize >= 0);
ASSERT(m_nMaxSize >= 0);
ASSERT(m_nSize <= m_nMaxSize);
ASSERT(AfxIsValidAddress(m_pData, m_nMaxSize * sizeof(TYPE)));
}
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CList<TYPE, ARG_TYPE>
template<class TYPE, class ARG_TYPE>
class CList : public CObject
{
protected:
struct CNode
{
CNode* pNext;
CNode* pPrev;
TYPE data;
};
public:
// Construction
CList(int nBlockSize = 10);
// Attributes (head and tail)
// count of elements
int GetCount() const;
BOOL IsEmpty() const;
// peek at head or tail
TYPE& GetHead();
TYPE GetHead() const;
TYPE& GetTail();
TYPE GetTail() const;
// Operations
// get head or tail (and remove it) - don't call on empty list !
TYPE RemoveHead();
TYPE RemoveTail();
// add before head or after tail
POSITION AddHead(ARG_TYPE newElement);
POSITION AddTail(ARG_TYPE newElement);
// add another list of elements before head or after tail
void AddHead(CList* pNewList);
void AddTail(CList* pNewList);
// remove all elements
void RemoveAll();
// iteration
POSITION GetHeadPosition() const;
POSITION GetTailPosition() const;
TYPE& GetNext(POSITION& rPosition); // return *Position++
TYPE GetNext(POSITION& rPosition) const; // return *Position++
TYPE& GetPrev(POSITION& rPosition); // return *Position--
TYPE GetPrev(POSITION& rPosition) const; // return *Position--
// getting/modifying an element at a given position
TYPE& GetAt(POSITION position);
TYPE GetAt(POSITION position) const;
void SetAt(POSITION pos, ARG_TYPE newElement);
void RemoveAt(POSITION position);
// inserting before or after a given position
POSITION InsertBefore(POSITION position, ARG_TYPE newElement);
POSITION InsertAfter(POSITION position, ARG_TYPE newElement);
// helper functions (note: O(n) speed)
POSITION Find(ARG_TYPE searchValue, POSITION startAfter = NULL) const;
// defaults to starting at the HEAD, return NULL if not found
POSITION FindIndex(int nIndex) const;
// get the 'nIndex'th element (may return NULL)
// Implementation
protected:
CNode* m_pNodeHead;
CNode* m_pNodeTail;
int m_nCount;
CNode* m_pNodeFree;
struct CPlex* m_pBlocks;
int m_nBlockSize;
CNode* NewNode(CNode*, CNode*);
void FreeNode(CNode*);
public:
~CList();
void Serialize(CArchive&);
#ifdef _DEBUG
void Dump(CDumpContext&) const;
void AssertValid() const;
#endif
};
/////////////////////////////////////////////////////////////////////////////
// CList<TYPE, ARG_TYPE> inline functions
template<class TYPE, class ARG_TYPE>
AFX_INLINE int CList<TYPE, ARG_TYPE>::GetCount() const
{ return m_nCount; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE BOOL CList<TYPE, ARG_TYPE>::IsEmpty() const
{ return m_nCount == 0; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetHead()
{ ASSERT(m_pNodeHead != NULL);
return m_pNodeHead->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetHead() const
{ ASSERT(m_pNodeHead != NULL);
return m_pNodeHead->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetTail()
{ ASSERT(m_pNodeTail != NULL);
return m_pNodeTail->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetTail() const
{ ASSERT(m_pNodeTail != NULL);
return m_pNodeTail->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetHeadPosition() const
{ return (POSITION) m_pNodeHead; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE POSITION CList<TYPE, ARG_TYPE>::GetTailPosition() const
{ return (POSITION) m_pNodeTail; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) // return *Position++
{ CNode* pNode = (CNode*) rPosition;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
rPosition = (POSITION) pNode->pNext;
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetNext(POSITION& rPosition) const // return *Position++
{ CNode* pNode = (CNode*) rPosition;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
rPosition = (POSITION) pNode->pNext;
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) // return *Position--
{ CNode* pNode = (CNode*) rPosition;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
rPosition = (POSITION) pNode->pPrev;
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetPrev(POSITION& rPosition) const // return *Position--
{ CNode* pNode = (CNode*) rPosition;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
rPosition = (POSITION) pNode->pPrev;
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE& CList<TYPE, ARG_TYPE>::GetAt(POSITION position)
{ CNode* pNode = (CNode*) position;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE TYPE CList<TYPE, ARG_TYPE>::GetAt(POSITION position) const
{ CNode* pNode = (CNode*) position;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
return pNode->data; }
template<class TYPE, class ARG_TYPE>
AFX_INLINE void CList<TYPE, ARG_TYPE>::SetAt(POSITION pos, ARG_TYPE newElement)
{ CNode* pNode = (CNode*) pos;
ASSERT(AfxIsValidAddress(pNode, sizeof(CNode)));
pNode->data = newElement; }
template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::CList(int nBlockSize)
{
ASSERT(nBlockSize > 0);
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks = NULL;
m_nBlockSize = nBlockSize;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::RemoveAll()
{
ASSERT_VALID(this);
// destroy elements
CNode* pNode;
for (pNode = m_pNodeHead; pNode != NULL; pNode = pNode->pNext)
DestructElements<TYPE>(&pNode->data, 1);
m_nCount = 0;
m_pNodeHead = m_pNodeTail = m_pNodeFree = NULL;
m_pBlocks->FreeDataChain();
m_pBlocks = NULL;
}
template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::~CList()
{
RemoveAll();
ASSERT(m_nCount == 0);
}
/////////////////////////////////////////////////////////////////////////////
// Node helpers
//
// Implementation note: CNode's are stored in CPlex blocks and
// chained together. Free blocks are maintained in a singly linked list
// using the 'pNext' member of CNode with 'm_pNodeFree' as the head.
// Used blocks are maintained in a doubly linked list using both 'pNext'
// and 'pPrev' as links and 'm_pNodeHead' and 'm_pNodeTail'
// as the head/tail.
//
// We never free a CPlex block unless the List is destroyed or RemoveAll()
// is used - so the total number of CPlex blocks may grow large depending
// on the maximum past size of the list.
//
template<class TYPE, class ARG_TYPE>
CList<TYPE, ARG_TYPE>::CNode*
CList<TYPE, ARG_TYPE>::NewNode(CList::CNode* pPrev, CList::CNode* pNext)
{
if (m_pNodeFree == NULL)
{
// add another block
CPlex* pNewBlock = CPlex::Create(m_pBlocks, m_nBlockSize,
sizeof(CNode));
// chain them into free list
CNode* pNode = (CNode*) pNewBlock->data();
// free in reverse order to make it easier to debug
pNode += m_nBlockSize - 1;
for (int i = m_nBlockSize-1; i >= 0; i--, pNode--)
{
pNode->pNext = m_pNodeFree;
m_pNodeFree = pNode;
}
}
ASSERT(m_pNodeFree != NULL); // we must have something
CList::CNode* pNode = m_pNodeFree;
m_pNodeFree = m_pNodeFree->pNext;
pNode->pPrev = pPrev;
pNode->pNext = pNext;
m_nCount++;
ASSERT(m_nCount > 0); // make sure we don't overflow
ConstructElements<TYPE>(&pNode->data, 1);
return pNode;
}
template<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::FreeNode(CList::CNode* pNode)
{
DestructElements<TYPE>(&pNode->data, 1);
pNode->pNext = m_pNodeFree;
m_pNodeFree = pNode;
m_nCount--;
ASSERT(m_nCount >= 0); // make sure we don't underflow
// if no more elements, cleanup completely
if (m_nCount == 0)
RemoveAll();
}
template<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddHead(ARG_TYPE newElement)
{
ASSERT_VALID(this);
CNode* 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<class TYPE, class ARG_TYPE>
POSITION CList<TYPE, ARG_TYPE>::AddTail(ARG_TYPE newElement)
{
ASSERT_VALID(this);
CNode* 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<class TYPE, class ARG_TYPE>
void CList<TYPE, ARG_TYPE>::AddHead(CList* pNewList)
{
ASSERT_VALID(this);
ASSERT(pNewList != NULL);
ASSERT_VALID(pNewList);
// add a list of same elements to head (maintain order)
POSITION pos = pNewList->GetTailPosition();
while (pos != NULL)
AddHead(pNewList->GetPrev(pos));
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -