411 lines
9.3 KiB
C++
411 lines
9.3 KiB
C++
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2023
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
#include "MemoryUtils.h"
|
|
#include "StringExt.h"
|
|
#include "Hash.h"
|
|
#include "Utils.h"
|
|
|
|
namespace NSFontConverter
|
|
{
|
|
//------------------------------------------------------------------------
|
|
|
|
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);
|
|
}
|
|
}
|