Home | History | Annotate | Download | only in fxcrt
      1 // Copyright 2014 PDFium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
      6 
      7 #include "core/include/fxcrt/fx_basic.h"
      8 #include "plex.h"
      9 
     10 namespace {
     11 
     12 const uint8_t kFreeLength = 0xfe;
     13 const uint8_t kHasAllocatedBufferLength = 0xff;
     14 
     15 }  // namespace
     16 
     17 CFX_MapPtrToPtr::CFX_MapPtrToPtr(int nBlockSize)
     18     : m_pHashTable(NULL),
     19       m_nHashTableSize(17),
     20       m_nCount(0),
     21       m_pFreeList(NULL),
     22       m_pBlocks(NULL),
     23       m_nBlockSize(nBlockSize) {
     24   ASSERT(m_nBlockSize > 0);
     25 }
     26 void CFX_MapPtrToPtr::RemoveAll() {
     27   FX_Free(m_pHashTable);
     28   m_pHashTable = NULL;
     29   m_nCount = 0;
     30   m_pFreeList = NULL;
     31   m_pBlocks->FreeDataChain();
     32   m_pBlocks = NULL;
     33 }
     34 CFX_MapPtrToPtr::~CFX_MapPtrToPtr() {
     35   RemoveAll();
     36   ASSERT(m_nCount == 0);
     37 }
     38 FX_DWORD CFX_MapPtrToPtr::HashKey(void* key) const {
     39   return ((FX_DWORD)(uintptr_t)key) >> 4;
     40 }
     41 void CFX_MapPtrToPtr::GetNextAssoc(FX_POSITION& rNextPosition,
     42                                    void*& rKey,
     43                                    void*& rValue) const {
     44   ASSERT(m_pHashTable);
     45   CAssoc* pAssocRet = (CAssoc*)rNextPosition;
     46   ASSERT(pAssocRet);
     47   if (pAssocRet == (CAssoc*)-1) {
     48     for (FX_DWORD nBucket = 0; nBucket < m_nHashTableSize; nBucket++) {
     49       if ((pAssocRet = m_pHashTable[nBucket]) != NULL)
     50         break;
     51     }
     52     ASSERT(pAssocRet);
     53   }
     54   CAssoc* pAssocNext;
     55   if ((pAssocNext = pAssocRet->pNext) == NULL) {
     56     for (FX_DWORD nBucket = (HashKey(pAssocRet->key) % m_nHashTableSize) + 1;
     57          nBucket < m_nHashTableSize; nBucket++) {
     58       if ((pAssocNext = m_pHashTable[nBucket]) != NULL) {
     59         break;
     60       }
     61     }
     62   }
     63   rNextPosition = (FX_POSITION)pAssocNext;
     64   rKey = pAssocRet->key;
     65   rValue = pAssocRet->value;
     66 }
     67 FX_BOOL CFX_MapPtrToPtr::Lookup(void* key, void*& rValue) const {
     68   FX_DWORD nHash;
     69   CAssoc* pAssoc = GetAssocAt(key, nHash);
     70   if (!pAssoc) {
     71     return FALSE;
     72   }
     73   rValue = pAssoc->value;
     74   return TRUE;
     75 }
     76 void* CFX_MapPtrToPtr::GetValueAt(void* key) const {
     77   FX_DWORD nHash;
     78   CAssoc* pAssoc = GetAssocAt(key, nHash);
     79   if (!pAssoc) {
     80     return NULL;
     81   }
     82   return pAssoc->value;
     83 }
     84 void*& CFX_MapPtrToPtr::operator[](void* key) {
     85   FX_DWORD nHash;
     86   CAssoc* pAssoc;
     87   if ((pAssoc = GetAssocAt(key, nHash)) == NULL) {
     88     if (!m_pHashTable) {
     89       InitHashTable(m_nHashTableSize);
     90     }
     91     pAssoc = NewAssoc();
     92     pAssoc->key = key;
     93     pAssoc->pNext = m_pHashTable[nHash];
     94     m_pHashTable[nHash] = pAssoc;
     95   }
     96   return pAssoc->value;
     97 }
     98 CFX_MapPtrToPtr::CAssoc* CFX_MapPtrToPtr::GetAssocAt(void* key,
     99                                                      FX_DWORD& nHash) const {
    100   nHash = HashKey(key) % m_nHashTableSize;
    101   if (!m_pHashTable) {
    102     return NULL;
    103   }
    104   CAssoc* pAssoc;
    105   for (pAssoc = m_pHashTable[nHash]; pAssoc; pAssoc = pAssoc->pNext) {
    106     if (pAssoc->key == key)
    107       return pAssoc;
    108   }
    109   return NULL;
    110 }
    111 CFX_MapPtrToPtr::CAssoc* CFX_MapPtrToPtr::NewAssoc() {
    112   if (!m_pFreeList) {
    113     CFX_Plex* newBlock = CFX_Plex::Create(m_pBlocks, m_nBlockSize,
    114                                           sizeof(CFX_MapPtrToPtr::CAssoc));
    115     CFX_MapPtrToPtr::CAssoc* pAssoc =
    116         (CFX_MapPtrToPtr::CAssoc*)newBlock->data();
    117     pAssoc += m_nBlockSize - 1;
    118     for (int i = m_nBlockSize - 1; i >= 0; i--, pAssoc--) {
    119       pAssoc->pNext = m_pFreeList;
    120       m_pFreeList = pAssoc;
    121     }
    122   }
    123   CFX_MapPtrToPtr::CAssoc* pAssoc = m_pFreeList;
    124   m_pFreeList = m_pFreeList->pNext;
    125   m_nCount++;
    126   ASSERT(m_nCount > 0);
    127   pAssoc->key = 0;
    128   pAssoc->value = 0;
    129   return pAssoc;
    130 }
    131 void CFX_MapPtrToPtr::InitHashTable(FX_DWORD nHashSize, FX_BOOL bAllocNow) {
    132   ASSERT(m_nCount == 0);
    133   ASSERT(nHashSize > 0);
    134   FX_Free(m_pHashTable);
    135   m_pHashTable = NULL;
    136   if (bAllocNow) {
    137     m_pHashTable = FX_Alloc(CAssoc*, nHashSize);
    138   }
    139   m_nHashTableSize = nHashSize;
    140 }
    141 FX_BOOL CFX_MapPtrToPtr::RemoveKey(void* key) {
    142   if (!m_pHashTable) {
    143     return FALSE;
    144   }
    145   CAssoc** ppAssocPrev;
    146   ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
    147   CAssoc* pAssoc;
    148   for (pAssoc = *ppAssocPrev; pAssoc; pAssoc = pAssoc->pNext) {
    149     if (pAssoc->key == key) {
    150       *ppAssocPrev = pAssoc->pNext;
    151       FreeAssoc(pAssoc);
    152       return TRUE;
    153     }
    154     ppAssocPrev = &pAssoc->pNext;
    155   }
    156   return FALSE;
    157 }
    158 void CFX_MapPtrToPtr::FreeAssoc(CFX_MapPtrToPtr::CAssoc* pAssoc) {
    159   pAssoc->pNext = m_pFreeList;
    160   m_pFreeList = pAssoc;
    161   m_nCount--;
    162   ASSERT(m_nCount >= 0);
    163   if (m_nCount == 0) {
    164     RemoveAll();
    165   }
    166 }
    167 struct _CompactString {
    168   uint8_t m_CompactLen;
    169   uint8_t m_LenHigh;
    170   uint8_t m_LenLow;
    171   uint8_t m_Unused;
    172   uint8_t* m_pBuffer;
    173 };
    174 static void _CompactStringRelease(_CompactString* pCompact) {
    175   if (pCompact->m_CompactLen == kHasAllocatedBufferLength) {
    176     FX_Free(pCompact->m_pBuffer);
    177   }
    178 }
    179 static FX_BOOL _CompactStringSame(_CompactString* pCompact,
    180                                   const uint8_t* pStr,
    181                                   int len) {
    182   if (len < sizeof(_CompactString)) {
    183     if (pCompact->m_CompactLen != len) {
    184       return FALSE;
    185     }
    186     return FXSYS_memcmp(&pCompact->m_LenHigh, pStr, len) == 0;
    187   }
    188   if (pCompact->m_CompactLen != kHasAllocatedBufferLength ||
    189       pCompact->m_LenHigh * 256 + pCompact->m_LenLow != len) {
    190     return FALSE;
    191   }
    192   return FXSYS_memcmp(pCompact->m_pBuffer, pStr, len) == 0;
    193 }
    194 static void _CompactStringStore(_CompactString* pCompact,
    195                                 const uint8_t* pStr,
    196                                 int len) {
    197   if (len < (int)sizeof(_CompactString)) {
    198     pCompact->m_CompactLen = (uint8_t)len;
    199     FXSYS_memcpy(&pCompact->m_LenHigh, pStr, len);
    200     return;
    201   }
    202   pCompact->m_CompactLen = kHasAllocatedBufferLength;
    203   pCompact->m_LenHigh = len / 256;
    204   pCompact->m_LenLow = len % 256;
    205   pCompact->m_pBuffer = FX_Alloc(uint8_t, len);
    206   FXSYS_memcpy(pCompact->m_pBuffer, pStr, len);
    207 }
    208 static CFX_ByteStringC _CompactStringGet(_CompactString* pCompact) {
    209   if (pCompact->m_CompactLen == kHasAllocatedBufferLength) {
    210     return CFX_ByteStringC(pCompact->m_pBuffer,
    211                            pCompact->m_LenHigh * 256 + pCompact->m_LenLow);
    212   }
    213   if (pCompact->m_CompactLen == kFreeLength) {
    214     return CFX_ByteStringC();
    215   }
    216   return CFX_ByteStringC(&pCompact->m_LenHigh, pCompact->m_CompactLen);
    217 }
    218 #define CMAP_ALLOC_STEP 8
    219 #define CMAP_INDEX_SIZE 8
    220 CFX_CMapByteStringToPtr::CFX_CMapByteStringToPtr()
    221     : m_Buffer(sizeof(_CompactString) + sizeof(void*),
    222                CMAP_ALLOC_STEP,
    223                CMAP_INDEX_SIZE) {}
    224 CFX_CMapByteStringToPtr::~CFX_CMapByteStringToPtr() {
    225   RemoveAll();
    226 }
    227 void CFX_CMapByteStringToPtr::RemoveAll() {
    228   int size = m_Buffer.GetSize();
    229   for (int i = 0; i < size; i++) {
    230     _CompactStringRelease((_CompactString*)m_Buffer.GetAt(i));
    231   }
    232   m_Buffer.RemoveAll();
    233 }
    234 FX_POSITION CFX_CMapByteStringToPtr::GetStartPosition() const {
    235   int size = m_Buffer.GetSize();
    236   for (int i = 0; i < size; i++) {
    237     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(i);
    238     if (pKey->m_CompactLen != kFreeLength) {
    239       return (FX_POSITION)(uintptr_t)(i + 1);
    240     }
    241   }
    242   return NULL;
    243 }
    244 void CFX_CMapByteStringToPtr::GetNextAssoc(FX_POSITION& rNextPosition,
    245                                            CFX_ByteString& rKey,
    246                                            void*& rValue) const {
    247   if (!rNextPosition) {
    248     return;
    249   }
    250   int index = (int)(uintptr_t)rNextPosition - 1;
    251   _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
    252   rKey = _CompactStringGet(pKey);
    253   rValue = *(void**)(pKey + 1);
    254   index++;
    255   int size = m_Buffer.GetSize();
    256   while (index < size) {
    257     pKey = (_CompactString*)m_Buffer.GetAt(index);
    258     if (pKey->m_CompactLen != kFreeLength) {
    259       rNextPosition = (FX_POSITION)(uintptr_t)(index + 1);
    260       return;
    261     }
    262     index++;
    263   }
    264   rNextPosition = NULL;
    265 }
    266 void* CFX_CMapByteStringToPtr::GetNextValue(FX_POSITION& rNextPosition) const {
    267   if (!rNextPosition) {
    268     return NULL;
    269   }
    270   int index = (int)(uintptr_t)rNextPosition - 1;
    271   _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
    272   void* rValue = *(void**)(pKey + 1);
    273   index++;
    274   int size = m_Buffer.GetSize();
    275   while (index < size) {
    276     pKey = (_CompactString*)m_Buffer.GetAt(index);
    277     if (pKey->m_CompactLen != kFreeLength) {
    278       rNextPosition = (FX_POSITION)(uintptr_t)(index + 1);
    279       return rValue;
    280     }
    281     index++;
    282   }
    283   rNextPosition = NULL;
    284   return rValue;
    285 }
    286 FX_BOOL _CMapLookupCallback(void* param, void* pData) {
    287   return !_CompactStringSame((_CompactString*)pData,
    288                              ((CFX_ByteStringC*)param)->GetPtr(),
    289                              ((CFX_ByteStringC*)param)->GetLength());
    290 }
    291 FX_BOOL CFX_CMapByteStringToPtr::Lookup(const CFX_ByteStringC& key,
    292                                         void*& rValue) const {
    293   void* p = m_Buffer.Iterate(_CMapLookupCallback, (void*)&key);
    294   if (!p) {
    295     return FALSE;
    296   }
    297   rValue = *(void**)((_CompactString*)p + 1);
    298   return TRUE;
    299 }
    300 void CFX_CMapByteStringToPtr::SetAt(const CFX_ByteStringC& key, void* value) {
    301   ASSERT(value);
    302   int key_len = key.GetLength();
    303   int size = m_Buffer.GetSize();
    304   for (int index = 0; index < size; index++) {
    305     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
    306     if (!_CompactStringSame(pKey, key.GetPtr(), key_len)) {
    307       continue;
    308     }
    309     *(void**)(pKey + 1) = value;
    310     return;
    311   }
    312   for (int index = 0; index < size; index++) {
    313     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
    314     if (pKey->m_CompactLen != kFreeLength) {
    315       continue;
    316     }
    317     _CompactStringStore(pKey, key.GetPtr(), key_len);
    318     *(void**)(pKey + 1) = value;
    319     return;
    320   }
    321   _CompactString* pKey = (_CompactString*)m_Buffer.Add();
    322   _CompactStringStore(pKey, key.GetPtr(), key_len);
    323   *(void**)(pKey + 1) = value;
    324 }
    325 void CFX_CMapByteStringToPtr::AddValue(const CFX_ByteStringC& key,
    326                                        void* value) {
    327   ASSERT(value);
    328   _CompactString* pKey = (_CompactString*)m_Buffer.Add();
    329   _CompactStringStore(pKey, key.GetPtr(), key.GetLength());
    330   *(void**)(pKey + 1) = value;
    331 }
    332 void CFX_CMapByteStringToPtr::RemoveKey(const CFX_ByteStringC& key) {
    333   int key_len = key.GetLength();
    334   int size = m_Buffer.GetSize();
    335   for (int index = 0; index < size; index++) {
    336     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
    337     if (!_CompactStringSame(pKey, key.GetPtr(), key_len)) {
    338       continue;
    339     }
    340     _CompactStringRelease(pKey);
    341     pKey->m_CompactLen = kFreeLength;
    342     return;
    343   }
    344 }
    345 int CFX_CMapByteStringToPtr::GetCount() const {
    346   int count = 0;
    347   int size = m_Buffer.GetSize();
    348   for (int i = 0; i < size; i++) {
    349     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(i);
    350     if (pKey->m_CompactLen != kFreeLength) {
    351       count++;
    352     }
    353   }
    354   return count;
    355 }
    356