📄 spcoll.cpp
字号:
// insert new value in the gap
SP_ASSERT(nIndex + nCount <= m_nSize);
while (nCount--)
m_pData[nIndex++] = newElement;
}
void CSPStringArray::RemoveAt(int nIndex, int nCount /* = 1 */)
{
SP_ASSERT_VALID(this);
SP_ASSERT(nIndex >= 0);
SP_ASSERT(nCount >= 0);
SP_ASSERT(nIndex + nCount <= m_nSize);
// just remove a range
int nMoveCount = m_nSize - (nIndex + nCount);
SPDestructElements(&m_pData[nIndex], nCount);
if (nMoveCount)
memcpy(&m_pData[nIndex], &m_pData[nIndex + nCount],
nMoveCount * sizeof(CSPString));
m_nSize -= nCount;
}
void CSPStringArray::InsertAt(int nStartIndex, CSPStringArray* pNewArray)
{
SP_ASSERT_VALID(this);
SP_ASSERT(pNewArray != NULL);
SP_ASSERT_VALID(pNewArray);
SP_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));
}
}
CSPStringArray * CSPStringArray::m_pSortSPStringArray = NULL;
int SortSPString(const void *p1,const void *p2)
{
if( NULL == p1 || NULL == p2 )
return 0;
DWORD dw1 = *(DWORD *)p1;
DWORD dw2 = *(DWORD *)p2;
if( NULL == CSPStringArray::m_pSortSPStringArray
|| dw1 < 0 || dw1 >= (DWORD)CSPStringArray::m_pSortSPStringArray->GetSize()
|| dw2 < 0 || dw2 >= (DWORD)CSPStringArray::m_pSortSPStringArray->GetSize() )
{
SP_ASSERT(FALSE);
return 0;
}
return strcmp(CSPStringArray::m_pSortSPStringArray->ElementAt(dw1),
CSPStringArray::m_pSortSPStringArray->ElementAt(dw2) );
}
BOOL CSPStringArray::GetSortIDArray( CSPDWordArray & adwSortID )
{
adwSortID.SetSize( 0, GetSize() + 1 );
for( DWORD i=0; i<(DWORD)GetSize(); i++ )
adwSortID.Add( i );
m_pSortSPStringArray = this;
if( adwSortID.GetData() )
qsort( adwSortID.GetData(), adwSortID.GetSize(), sizeof(DWORD), SortSPString );
m_pSortSPStringArray = NULL;
return TRUE;
}
void CSPStringArray::Serialize(CSPArchive& ar)
{
SP_ASSERT_VALID(this);
if (ar.IsStoring())
{
ar.WriteCount(GetSize());
for (int i = 0; i < m_nSize; i++)
ar << m_pData[i];
}
else
{
DWORD nOldSize = ar.ReadCount();
SetSize(nOldSize);
for (DWORD i = 0; i < nOldSize; i++)
ar >> m_pData[i];
}
}
void CSPStringArray::SPConstructElements(CSPString* pElements, int nCount)
{
SP_ASSERT(nCount == 0 ||
SP_IsValidAddress(pElements, nCount * sizeof(CSPString)));
for (; nCount--; ++pElements)
memcpy(pElements, &afxEmptySPString, sizeof(*pElements));
}
void CSPStringArray::SPDestructElements(CSPString* pElements, int nCount)
{
SP_ASSERT(nCount == 0 ||
SP_IsValidAddress(pElements, nCount * sizeof(CSPString)));
// call the destructor(s)
for (; nCount--; pElements++)
pElements->~CSPString();
}
// Diagnostics
#ifdef _DEBUG
void CSPStringArray::Dump() const
{
Object::Dump( );
}
void CSPStringArray::AssertValid() const
{
Object::AssertValid();
if (m_pData == NULL)
{
SP_ASSERT(m_nSize == 0);
SP_ASSERT(m_nMaxSize == 0);
}
else
{
SP_ASSERT(m_nSize >= 0);
SP_ASSERT(m_nMaxSize >= 0);
SP_ASSERT(m_nSize <= m_nMaxSize);
SP_ASSERT(SP_IsValidAddress(m_pData, m_nMaxSize * sizeof(CSPString)));
}
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CSPPlex
CSPPlex* PASCAL CSPPlex::Create(CSPPlex*& pHead, UINT nMax, UINT cbElement)
{
SP_ASSERT(nMax > 0 && cbElement > 0);
CSPPlex* p = (CSPPlex*) new BYTE[sizeof(CSPPlex) + nMax * cbElement];
// may throw exception
p->pNext = pHead;
pHead = p; // change head (adds in reverse order for simplicity)
return p;
}
void CSPPlex::FreeDataChain() // free this one and links
{
CSPPlex* p = this;
while (p != NULL)
{
BYTE* bytes = (BYTE*) p;
CSPPlex* pNext = p->pNext;
delete[] bytes;
p = pNext;
}
}
/////////////////////////////////////////////////////////////////////////////
// CSPMapStringToPtr out-of-line functions
CSPMapStringToPtr::CSPMapStringToPtr(int nBlockSize)
{
SP_ASSERT(nBlockSize > 0);
m_pHashTable = NULL;
m_nHashTableSize = 17; // default size
m_nCount = 0;
m_pFreeList = NULL;
m_pBlocks = NULL;
m_nBlockSize = nBlockSize;
}
inline UINT CSPMapStringToPtr::HashKey(LPCTSTR key) const
{
UINT nHash = 0;
while (*key)
nHash = (nHash<<5) + nHash + *key++;
return nHash;
}
void CSPMapStringToPtr::InitHashTable(
UINT nHashSize, BOOL bAllocNow)
//
// Used to force allocation of a hash table or to override the default
// hash table size of (which is fairly small)
{
SP_ASSERT_VALID(this);
SP_ASSERT(m_nCount == 0);
SP_ASSERT(nHashSize > 0);
if (m_pHashTable != NULL)
{
// free hash table
delete[] m_pHashTable;
m_pHashTable = NULL;
}
if (bAllocNow)
{
m_pHashTable = new CAssoc* [nHashSize];
memset(m_pHashTable, 0, sizeof(CAssoc*) * nHashSize);
}
m_nHashTableSize = nHashSize;
}
static inline void DestructElement(CSPString* pOldData)
{
pOldData->~CSPString();
}
void CSPMapStringToPtr::RemoveAll()
{
SP_ASSERT_VALID(this);
if (m_pHashTable != NULL)
{
// destroy elements
for (UINT nHash = 0; nHash < m_nHashTableSize; nHash++)
{
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
pAssoc = pAssoc->pNext)
{
DestructElement(&pAssoc->key); // free up string data
}
}
// free hash table
delete [] m_pHashTable;
m_pHashTable = NULL;
}
m_nCount = 0;
m_pFreeList = NULL;
m_pBlocks->FreeDataChain();
m_pBlocks = NULL;
}
CSPMapStringToPtr::~CSPMapStringToPtr()
{
RemoveAll();
SP_ASSERT(m_nCount == 0);
}
// Assoc helpers
// same as CList implementation except we store CAssoc's not CNode's
// and CAssoc's are singly linked all the time
CSPMapStringToPtr::CAssoc*
CSPMapStringToPtr::NewAssoc()
{
if (m_pFreeList == NULL)
{
// add another block
CSPPlex* newBlock = CSPPlex::Create(m_pBlocks, m_nBlockSize,
sizeof(CSPMapStringToPtr::CAssoc));
// chain them into free list
CSPMapStringToPtr::CAssoc* pAssoc =
(CSPMapStringToPtr::CAssoc*) newBlock->data();
// free in reverse order to make it easier to debug
pAssoc += m_nBlockSize - 1;
for (int i = m_nBlockSize-1; i >= 0; i--, pAssoc--)
{
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
}
}
SP_ASSERT(m_pFreeList != NULL); // we must have something
CSPMapStringToPtr::CAssoc* pAssoc = m_pFreeList;
m_pFreeList = m_pFreeList->pNext;
m_nCount++;
SP_ASSERT(m_nCount > 0); // make sure we don't overflow
//CSPString emptyString;
//memcpy(&pAssoc->key, &emptyString, sizeof(CSPString));
memcpy(&pAssoc->key, &afxEmptySPString, sizeof(pAssoc->key));
pAssoc->value = 0;
return pAssoc;
}
void CSPMapStringToPtr::FreeAssoc(CSPMapStringToPtr::CAssoc* pAssoc)
{
DestructElement(&pAssoc->key); // free up string data
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
m_nCount--;
SP_ASSERT(m_nCount >= 0); // make sure we don't underflow
// if no more elements, cleanup completely
if (m_nCount == 0)
RemoveAll();
}
CSPMapStringToPtr::CAssoc*
CSPMapStringToPtr::GetAssocAt(LPCTSTR key, UINT& nHash) const
// find association (or return NULL)
{
nHash = HashKey(key) % m_nHashTableSize;
if (m_pHashTable == NULL)
return NULL;
// see if it exists
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext)
{
if (pAssoc->key == key)
return pAssoc;
}
return NULL;
}
BOOL CSPMapStringToPtr::Lookup(LPCTSTR key, void*& rValue) const
{
SP_ASSERT_VALID(this);
UINT nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
if (pAssoc == NULL)
return FALSE; // not in map
rValue = pAssoc->value;
return TRUE;
}
BOOL CSPMapStringToPtr::LookupKey(LPCTSTR key, LPCTSTR& rKey) const
{
SP_ASSERT_VALID(this);
UINT nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
if (pAssoc == NULL)
return FALSE; // not in map
rKey = pAssoc->key;
return TRUE;
}
void*& CSPMapStringToPtr::operator[](LPCTSTR key)
{
SP_ASSERT_VALID(this);
UINT nHash;
CAssoc* pAssoc;
if ((pAssoc = GetAssocAt(key, nHash)) == NULL)
{
if (m_pHashTable == NULL)
InitHashTable(m_nHashTableSize);
// it doesn't exist, add a new Association
pAssoc = NewAssoc();
pAssoc->nHashValue = nHash;
pAssoc->key = key;
// 'pAssoc->value' is a constructed object, nothing more
// put into hash table
pAssoc->pNext = m_pHashTable[nHash];
m_pHashTable[nHash] = pAssoc;
}
return pAssoc->value; // return new reference
}
BOOL CSPMapStringToPtr::RemoveKey(LPCTSTR key)
// remove key - return TRUE if removed
{
SP_ASSERT_VALID(this);
if (m_pHashTable == NULL)
return FALSE; // nothing in the table
CAssoc** ppAssocPrev;
ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
CAssoc* pAssoc;
for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext)
{
if (pAssoc->key == key)
{
// remove it
*ppAssocPrev = pAssoc->pNext; // remove from list
FreeAssoc(pAssoc);
return TRUE;
}
ppAssocPrev = &pAssoc->pNext;
}
return FALSE; // not found
}
// Iterating
void CSPMapStringToPtr::GetNextAssoc(SPPOSITION& rNextPosition,
CSPString& rKey, void*& rValue) const
{
SP_ASSERT_VALID(this);
SP_ASSERT(m_pHashTable != NULL); // never call on empty map
CAssoc* pAssocRet = (CAssoc*)rNextPosition;
SP_ASSERT(pAssocRet != NULL);
if (pAssocRet == (CAssoc*) BEFORE_START_SPPOSITION)
{
// find the first association
for (UINT nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
break;
SP_ASSERT(pAssocRet != NULL); // must find something
}
// find next association
SP_ASSERT(SP_IsValidAddress(pAssocRet, sizeof(CAssoc)));
CAssoc* pAssocNext;
if ((pAssocNext = pAssocRet->pNext) == NULL)
{
// go to next bucket
for (UINT nBucket = pAssocRet->nHashValue + 1;
nBucket < m_nHashTableSize; nBucket++)
if ((pAssocNext = m_pHashTable[nBucket]) != NULL)
break;
}
rNextPosition = (SPPOSITION) pAssocNext;
// fill in return data
rKey = pAssocRet->key;
rValue = pAssocRet->value;
}
// Diagnostics
#ifdef _DEBUG
void CSPMapStringToPtr::Dump( ) const
{
Object::Dump();
}
void CSPMapStringToPtr::AssertValid() const
{
Object::AssertValid();
SP_ASSERT(m_nHashTableSize > 0);
SP_ASSERT(m_nCount == 0 || m_pHashTable != NULL);
// non-empty map should have hash table
}
#endif //_DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -