mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
378 lines
7.5 KiB
C++
378 lines
7.5 KiB
C++
#include "stdafx.h"
|
|
|
|
#include "MemoryUtils.h"
|
|
#include "StringExt.h"
|
|
#include "Hash.h"
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
struct THashBucket
|
|
{
|
|
StringExt *seKey;
|
|
union
|
|
{
|
|
void *p;
|
|
int i;
|
|
} uValue;
|
|
THashBucket *pNext;
|
|
};
|
|
|
|
struct THashIter
|
|
{
|
|
int nHashIndex;
|
|
THashBucket *pBucket;
|
|
};
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
CHash::CHash(BOOL bDeleteKeys)
|
|
{
|
|
m_bDeleteKeys = bDeleteKeys;
|
|
m_nBucketsCount = 7;
|
|
m_ppTable = (THashBucket **)MemUtilsMallocArray( m_nBucketsCount, sizeof(THashBucket *));
|
|
for ( int nHashIndex = 0; nHashIndex < m_nBucketsCount; ++nHashIndex )
|
|
m_ppTable[ nHashIndex ] = NULL;
|
|
m_nLength = 0;
|
|
}
|
|
|
|
CHash::~CHash()
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
|
|
for ( int nHashIndex = 0; nHashIndex < m_nBucketsCount; ++nHashIndex )
|
|
{
|
|
while ( m_ppTable[ nHashIndex ] )
|
|
{
|
|
pBucket = m_ppTable[ nHashIndex ];
|
|
m_ppTable[ nHashIndex ] = pBucket->pNext;
|
|
if (m_bDeleteKeys)
|
|
{
|
|
delete pBucket->seKey;
|
|
}
|
|
delete pBucket;
|
|
}
|
|
}
|
|
MemUtilsFree( m_ppTable );
|
|
}
|
|
|
|
void CHash::Add(StringExt *seKey, void *pValue)
|
|
{
|
|
if ( m_nLength >= m_nBucketsCount )
|
|
Expand();
|
|
|
|
THashBucket *pBucket = new THashBucket;
|
|
pBucket->seKey = seKey;
|
|
pBucket->uValue.p = pValue;
|
|
int nHashIndex = Hash( seKey );
|
|
pBucket->pNext = m_ppTable[ nHashIndex ];
|
|
m_ppTable[ nHashIndex ] = pBucket;
|
|
++m_nLength;
|
|
}
|
|
|
|
void CHash::Add(StringExt *seKey, int nValue)
|
|
{
|
|
if ( m_nLength >= m_nBucketsCount )
|
|
Expand();
|
|
|
|
THashBucket *pBucket = new THashBucket;
|
|
pBucket->seKey = seKey;
|
|
pBucket->uValue.i = nValue;
|
|
int nHashIndex = Hash( seKey );
|
|
pBucket->pNext = m_ppTable[ nHashIndex ];
|
|
m_ppTable[ nHashIndex ] = pBucket;
|
|
++m_nLength;
|
|
}
|
|
|
|
void CHash::Replace(StringExt *seKey, void *pValue)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( ( pBucket = Find( seKey, &nHashIndex ) ) )
|
|
{
|
|
pBucket->uValue.p = pValue;
|
|
delete seKey;
|
|
}
|
|
else
|
|
Add( seKey, pValue);
|
|
}
|
|
|
|
void CHash::Replace(StringExt *seKey, int nValue)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( ( pBucket = Find( seKey, &nHashIndex ) ) )
|
|
{
|
|
pBucket->uValue.i = nValue;
|
|
delete seKey;
|
|
}
|
|
else
|
|
Add( seKey, nValue);
|
|
}
|
|
|
|
void *CHash::Lookup(StringExt *seKey)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( seKey, &nHashIndex ) ) )
|
|
return NULL;
|
|
return pBucket->uValue.p;
|
|
}
|
|
|
|
int CHash::LookupInt(StringExt *seKey)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( seKey, &nHashIndex ) ) )
|
|
return 0;
|
|
|
|
return pBucket->uValue.i;
|
|
}
|
|
|
|
void *CHash::Lookup(char *sKey)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( sKey, &nHashIndex ) ) )
|
|
return NULL;
|
|
return pBucket->uValue.p;
|
|
}
|
|
|
|
int CHash::LookupInt(char *sKey)
|
|
{
|
|
THashBucket *pBucket = NULL;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( sKey, &nHashIndex ) ) )
|
|
return 0;
|
|
|
|
return pBucket->uValue.i;
|
|
}
|
|
|
|
void *CHash::Remove(StringExt *seKey)
|
|
{
|
|
THashBucket *pBucket;
|
|
THashBucket **ppBucket;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( seKey, &nHashIndex ) ) )
|
|
return NULL;
|
|
|
|
ppBucket = &m_ppTable[ nHashIndex ];
|
|
while ( *ppBucket != pBucket )
|
|
ppBucket = &((*ppBucket)->pNext);
|
|
|
|
*ppBucket = pBucket->pNext;
|
|
if ( m_bDeleteKeys )
|
|
delete pBucket->seKey;
|
|
void *pValue = pBucket->uValue.p;
|
|
delete pBucket;
|
|
--m_nLength;
|
|
return pValue;
|
|
}
|
|
|
|
int CHash::RemoveInt(StringExt *seKey)
|
|
{
|
|
THashBucket *pBucket;
|
|
THashBucket **ppBucket;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( seKey, &nHashIndex) ) )
|
|
return 0;
|
|
|
|
ppBucket = &m_ppTable[ nHashIndex ];
|
|
while ( *ppBucket != pBucket )
|
|
ppBucket = &((*ppBucket)->pNext);
|
|
|
|
*ppBucket = pBucket->pNext;
|
|
if (m_bDeleteKeys)
|
|
delete pBucket->seKey;
|
|
|
|
int nValue = pBucket->uValue.i;
|
|
delete pBucket;
|
|
--m_nLength;
|
|
return nValue;
|
|
}
|
|
|
|
void *CHash::Remove(char *sKey)
|
|
{
|
|
THashBucket *pBucket;
|
|
THashBucket **ppBucket;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( sKey, &nHashIndex ) ) )
|
|
return NULL;
|
|
ppBucket = &m_ppTable[ nHashIndex ];
|
|
while ( *ppBucket != pBucket )
|
|
ppBucket = &((*ppBucket)->pNext);
|
|
|
|
*ppBucket = pBucket->pNext;
|
|
|
|
if (m_bDeleteKeys)
|
|
delete pBucket->pNext;
|
|
|
|
void *pValue = pBucket->uValue.p;
|
|
delete pBucket;
|
|
--m_nLength;
|
|
return pValue;
|
|
}
|
|
|
|
int CHash::RemoveInt(char *sKey)
|
|
{
|
|
THashBucket *pBucket;
|
|
THashBucket **ppBucket;
|
|
int nHashIndex = 0;
|
|
|
|
if ( !( pBucket = Find( sKey, &nHashIndex ) ) )
|
|
return 0;
|
|
|
|
ppBucket = &m_ppTable[ nHashIndex ];
|
|
while (*ppBucket != pBucket )
|
|
ppBucket = &((*ppBucket)->pNext);
|
|
|
|
*ppBucket = pBucket->pNext;
|
|
if ( m_bDeleteKeys )
|
|
delete pBucket->seKey;
|
|
|
|
int nValue = pBucket->uValue.i;
|
|
delete pBucket;
|
|
--m_nLength;
|
|
return nValue;
|
|
}
|
|
|
|
void CHash::StartIter(THashIter **ppIter)
|
|
{
|
|
*ppIter = new THashIter;
|
|
(*ppIter)->nHashIndex = -1;
|
|
(*ppIter)->pBucket = NULL;
|
|
}
|
|
|
|
BOOL CHash::GetNext(THashIter **ppIter, StringExt **pseKey, void **ppValue)
|
|
{
|
|
if (!*ppIter)
|
|
return FALSE;
|
|
|
|
if ((*ppIter)->pBucket)
|
|
(*ppIter)->pBucket = (*ppIter)->pBucket->pNext;
|
|
|
|
while (!(*ppIter)->pBucket)
|
|
{
|
|
if (++(*ppIter)->nHashIndex == m_nBucketsCount)
|
|
{
|
|
delete *ppIter;
|
|
*ppIter = NULL;
|
|
return FALSE;
|
|
}
|
|
(*ppIter)->pBucket = m_ppTable[(*ppIter)->nHashIndex];
|
|
}
|
|
*pseKey = (*ppIter)->pBucket->seKey;
|
|
*ppValue = (*ppIter)->pBucket->uValue.p;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CHash::GetNext(THashIter **ppIter, StringExt **pseKey, int *pnValue)
|
|
{
|
|
if (!*ppIter)
|
|
return FALSE;
|
|
|
|
if ((*ppIter)->pBucket)
|
|
(*ppIter)->pBucket = (*ppIter)->pBucket->pNext;
|
|
|
|
while (!(*ppIter)->pBucket)
|
|
{
|
|
if (++(*ppIter)->nHashIndex == m_nBucketsCount)
|
|
{
|
|
delete *ppIter;
|
|
*ppIter = NULL;
|
|
return FALSE;
|
|
}
|
|
(*ppIter)->pBucket = m_ppTable[(*ppIter)->nHashIndex ];
|
|
}
|
|
*pseKey = (*ppIter)->pBucket->seKey;
|
|
*pnValue = (*ppIter)->pBucket->uValue.i;
|
|
return TRUE;
|
|
}
|
|
|
|
void CHash::DeleteIter(THashIter **ppIter)
|
|
{
|
|
delete *ppIter;
|
|
*ppIter = NULL;
|
|
}
|
|
|
|
void CHash::Expand()
|
|
{
|
|
int nHashIndex = 0;
|
|
|
|
int nOldSize = m_nBucketsCount;
|
|
THashBucket **ppOldTab = m_ppTable;
|
|
m_nBucketsCount = 2 * m_nBucketsCount + 1;
|
|
m_ppTable = (THashBucket **)MemUtilsMallocArray( m_nBucketsCount, sizeof(THashBucket *) );
|
|
for ( nHashIndex = 0; nHashIndex < m_nBucketsCount; ++nHashIndex )
|
|
m_ppTable[ nHashIndex ] = NULL;
|
|
|
|
for (int nIndex = 0; nIndex < nOldSize; ++nIndex )
|
|
{
|
|
while ( ppOldTab[nIndex] )
|
|
{
|
|
THashBucket *pBucket = ppOldTab[ nIndex ];
|
|
ppOldTab[ nIndex ] = ppOldTab[ nIndex ]->pNext;
|
|
nHashIndex = Hash( pBucket->seKey );
|
|
pBucket->pNext = m_ppTable[ nHashIndex ];
|
|
m_ppTable[ nHashIndex ] = pBucket;
|
|
}
|
|
}
|
|
MemUtilsFree( ppOldTab );
|
|
}
|
|
|
|
THashBucket *CHash::Find(StringExt *seKey, int *pnHashIndex)
|
|
{
|
|
THashBucket *pBucket;
|
|
|
|
*pnHashIndex = Hash( seKey );
|
|
for ( pBucket = m_ppTable[ *pnHashIndex ]; pBucket; pBucket = pBucket->pNext )
|
|
{
|
|
if ( !pBucket->seKey->Compare( seKey ) )
|
|
return pBucket;
|
|
}
|
|
return NULL;
|
|
}
|
|
THashBucket *CHash::Find(char *sKey, int *pnHashIndex)
|
|
{
|
|
THashBucket *pBucket;
|
|
|
|
*pnHashIndex = Hash( sKey );
|
|
for ( pBucket = m_ppTable[ *pnHashIndex ]; pBucket; pBucket = pBucket->pNext )
|
|
{
|
|
if ( !pBucket->seKey->Compare( sKey ) )
|
|
return pBucket;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
int CHash::Hash(StringExt *seKey)
|
|
{
|
|
char *sTemp;
|
|
unsigned int nHash = 0;
|
|
int nIndex;
|
|
|
|
for ( sTemp = seKey->GetBuffer(), nIndex = 0; nIndex < seKey->GetLength(); ++sTemp, ++nIndex )
|
|
nHash = 17 * nHash + (int)(*sTemp & 0xff);
|
|
|
|
return (int)(nHash % m_nBucketsCount);
|
|
}
|
|
|
|
int CHash::Hash(char *sKey)
|
|
{
|
|
char *sTemp;
|
|
unsigned int nHash = 0;
|
|
|
|
for ( sTemp = sKey; *sTemp; ++sTemp )
|
|
nHash = 17 * nHash + (int)(*sTemp & 0xff);
|
|
|
|
return (int)(nHash % m_nBucketsCount);
|
|
}
|