// 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; } 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, 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; } 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(); } }