blob: 48fb97082d8ad8481936bbc0dd1b05511438401b [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "core/fxcrt/fx_basic.h"
#include "core/fxcrt/plex.h"
CFX_MapPtrToPtr::CFX_MapPtrToPtr(int nBlockSize)
: m_pHashTable(nullptr),
m_nHashTableSize(17),
m_nCount(0),
m_pFreeList(nullptr),
m_pBlocks(nullptr),
m_nBlockSize(nBlockSize) {
ASSERT(m_nBlockSize > 0);
}
void CFX_MapPtrToPtr::RemoveAll() {
FX_Free(m_pHashTable);
m_pHashTable = nullptr;
m_nCount = 0;
m_pFreeList = nullptr;
if (m_pBlocks) {
m_pBlocks->FreeDataChain();
m_pBlocks = nullptr;
}
}
CFX_MapPtrToPtr::~CFX_MapPtrToPtr() {
RemoveAll();
ASSERT(m_nCount == 0);
}
uint32_t CFX_MapPtrToPtr::HashKey(void* key) const {
return ((uint32_t)(uintptr_t)key) >> 4;
}
void CFX_MapPtrToPtr::GetNextAssoc(FX_POSITION& rNextPosition,
void*& rKey,
void*& rValue) const {
ASSERT(m_pHashTable);
CAssoc* pAssocRet = (CAssoc*)rNextPosition;
ASSERT(pAssocRet);
if (pAssocRet == (CAssoc*)-1) {
for (uint32_t nBucket = 0; nBucket < m_nHashTableSize; nBucket++) {
pAssocRet = m_pHashTable[nBucket];
if (pAssocRet)
break;
}
ASSERT(pAssocRet);
}
CAssoc* pAssocNext = pAssocRet->pNext;
for (uint32_t nBucket = (HashKey(pAssocRet->key) % m_nHashTableSize) + 1;
nBucket < m_nHashTableSize && !pAssocNext; nBucket++) {
pAssocNext = m_pHashTable[nBucket];
}
rNextPosition = (FX_POSITION)pAssocNext;
rKey = pAssocRet->key;
rValue = pAssocRet->value;
}
FX_BOOL CFX_MapPtrToPtr::Lookup(void* key, void*& rValue) const {
uint32_t nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
if (!pAssoc) {
return FALSE;
}
rValue = pAssoc->value;
return TRUE;
}
void* CFX_MapPtrToPtr::GetValueAt(void* key) const {
uint32_t nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
return pAssoc ? pAssoc->value : nullptr;
}
void*& CFX_MapPtrToPtr::operator[](void* key) {
uint32_t nHash;
CAssoc* pAssoc = GetAssocAt(key, nHash);
if (!pAssoc) {
if (!m_pHashTable)
InitHashTable(m_nHashTableSize);
pAssoc = NewAssoc();
pAssoc->key = key;
pAssoc->pNext = m_pHashTable[nHash];
m_pHashTable[nHash] = pAssoc;
}
return pAssoc->value;
}
CFX_MapPtrToPtr::CAssoc* CFX_MapPtrToPtr::GetAssocAt(void* key,
uint32_t& nHash) const {
nHash = HashKey(key) % m_nHashTableSize;
if (!m_pHashTable) {
return nullptr;
}
CAssoc* pAssoc;
for (pAssoc = m_pHashTable[nHash]; pAssoc; pAssoc = pAssoc->pNext) {
if (pAssoc->key == key)
return pAssoc;
}
return nullptr;
}
CFX_MapPtrToPtr::CAssoc* CFX_MapPtrToPtr::NewAssoc() {
if (!m_pFreeList) {
CFX_Plex* newBlock = CFX_Plex::Create(m_pBlocks, m_nBlockSize,
sizeof(CFX_MapPtrToPtr::CAssoc));
CFX_MapPtrToPtr::CAssoc* pAssoc =
(CFX_MapPtrToPtr::CAssoc*)newBlock->data();
pAssoc += m_nBlockSize - 1;
for (int i = m_nBlockSize - 1; i >= 0; i--, pAssoc--) {
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
}
}
CFX_MapPtrToPtr::CAssoc* pAssoc = m_pFreeList;
m_pFreeList = m_pFreeList->pNext;
m_nCount++;
ASSERT(m_nCount > 0);
pAssoc->key = 0;
pAssoc->value = 0;
return pAssoc;
}
void CFX_MapPtrToPtr::InitHashTable(uint32_t nHashSize, FX_BOOL bAllocNow) {
ASSERT(m_nCount == 0);
ASSERT(nHashSize > 0);
FX_Free(m_pHashTable);
m_pHashTable = nullptr;
if (bAllocNow) {
m_pHashTable = FX_Alloc(CAssoc*, nHashSize);
}
m_nHashTableSize = nHashSize;
}
FX_BOOL CFX_MapPtrToPtr::RemoveKey(void* key) {
if (!m_pHashTable) {
return FALSE;
}
CAssoc** ppAssocPrev;
ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
CAssoc* pAssoc;
for (pAssoc = *ppAssocPrev; pAssoc; pAssoc = pAssoc->pNext) {
if (pAssoc->key == key) {
*ppAssocPrev = pAssoc->pNext;
FreeAssoc(pAssoc);
return TRUE;
}
ppAssocPrev = &pAssoc->pNext;
}
return FALSE;
}
void CFX_MapPtrToPtr::FreeAssoc(CFX_MapPtrToPtr::CAssoc* pAssoc) {
pAssoc->pNext = m_pFreeList;
m_pFreeList = pAssoc;
m_nCount--;
ASSERT(m_nCount >= 0);
if (m_nCount == 0) {
RemoveAll();
}
}