Merge to XFA: Kill FXSYS_mem{cpy,cmp,set.move}{32,8}.
[pdfium.git] / core / src / fxcrt / fx_basic_maps.cpp
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 "../../include/fxcrt/fx_ext.h"
8 #include "plex.h"
9 static void ConstructElement(CFX_ByteString* pNewData)
10 {
11     new (pNewData) CFX_ByteString();
12 }
13 static void DestructElement(CFX_ByteString* pOldData)
14 {
15     pOldData->~CFX_ByteString();
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 {
25     ASSERT(m_nBlockSize > 0);
26 }
27 void CFX_MapPtrToPtr::RemoveAll()
28 {
29     if (m_pHashTable) {
30         FX_Free(m_pHashTable);
31         m_pHashTable = NULL;
32     }
33     m_nCount = 0;
34     m_pFreeList = NULL;
35     m_pBlocks->FreeDataChain();
36     m_pBlocks = NULL;
37 }
38 CFX_MapPtrToPtr::~CFX_MapPtrToPtr()
39 {
40     RemoveAll();
41     ASSERT(m_nCount == 0);
42 }
43 FX_DWORD CFX_MapPtrToPtr::HashKey(void* key) const
44 {
45     return ((FX_DWORD)(uintptr_t)key) >> 4;
46 }
47 void CFX_MapPtrToPtr::GetNextAssoc(FX_POSITION& rNextPosition, void*& rKey, void*& rValue) const
48 {
49     ASSERT(m_pHashTable != NULL);
50     CAssoc* pAssocRet = (CAssoc*)rNextPosition;
51     ASSERT(pAssocRet != NULL);
52     if (pAssocRet == (CAssoc*) - 1) {
53         for (FX_DWORD nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
54             if ((pAssocRet = m_pHashTable[nBucket]) != NULL) {
55                 break;
56             }
57         ASSERT(pAssocRet != NULL);
58     }
59     CAssoc* pAssocNext;
60     if ((pAssocNext = pAssocRet->pNext) == NULL) {
61         for (FX_DWORD nBucket = (HashKey(pAssocRet->key) % m_nHashTableSize) + 1; nBucket < m_nHashTableSize; nBucket ++) {
62             if ((pAssocNext = m_pHashTable[nBucket]) != NULL) {
63                 break;
64             }
65         }
66     }
67     rNextPosition = (FX_POSITION) pAssocNext;
68     rKey = pAssocRet->key;
69     rValue = pAssocRet->value;
70 }
71 FX_BOOL CFX_MapPtrToPtr::Lookup(void* key, void*& rValue) const
72 {
73     FX_DWORD nHash;
74     CAssoc* pAssoc = GetAssocAt(key, nHash);
75     if (pAssoc == NULL) {
76         return FALSE;
77     }
78     rValue = pAssoc->value;
79     return TRUE;
80 }
81 void* CFX_MapPtrToPtr::GetValueAt(void* key) const
82 {
83     FX_DWORD nHash;
84     CAssoc* pAssoc = GetAssocAt(key, nHash);
85     if (pAssoc == NULL) {
86         return NULL;
87     }
88     return pAssoc->value;
89 }
90 void*& CFX_MapPtrToPtr::operator[](void* key)
91 {
92     FX_DWORD nHash;
93     CAssoc* pAssoc;
94     if ((pAssoc = GetAssocAt(key, nHash)) == NULL) {
95         if (m_pHashTable == NULL) {
96             InitHashTable(m_nHashTableSize);
97         }
98         pAssoc = NewAssoc();
99         pAssoc->key = key;
100         pAssoc->pNext = m_pHashTable[nHash];
101         m_pHashTable[nHash] = pAssoc;
102     }
103     return pAssoc->value;
104 }
105 CFX_MapPtrToPtr::CAssoc*
106 CFX_MapPtrToPtr::GetAssocAt(void* key, FX_DWORD& nHash) const
107 {
108     nHash = HashKey(key) % m_nHashTableSize;
109     if (m_pHashTable == NULL) {
110         return NULL;
111     }
112     CAssoc* pAssoc;
113     for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
114         if (pAssoc->key == key) {
115             return pAssoc;
116         }
117     }
118     return NULL;
119 }
120 CFX_MapPtrToPtr::CAssoc*
121 CFX_MapPtrToPtr::NewAssoc()
122 {
123     if (m_pFreeList == NULL) {
124         CFX_Plex* newBlock = CFX_Plex::Create(m_pBlocks, m_nBlockSize, sizeof(CFX_MapPtrToPtr::CAssoc));
125         CFX_MapPtrToPtr::CAssoc* pAssoc = (CFX_MapPtrToPtr::CAssoc*)newBlock->data();
126         pAssoc += m_nBlockSize - 1;
127         for (int i = m_nBlockSize - 1; i >= 0; i--, pAssoc--) {
128             pAssoc->pNext = m_pFreeList;
129             m_pFreeList = pAssoc;
130         }
131     }
132     ASSERT(m_pFreeList != NULL);
133     CFX_MapPtrToPtr::CAssoc* pAssoc = m_pFreeList;
134     m_pFreeList = m_pFreeList->pNext;
135     m_nCount++;
136     ASSERT(m_nCount > 0);
137     pAssoc->key = 0;
138     pAssoc->value = 0;
139     return pAssoc;
140 }
141 void CFX_MapPtrToPtr::InitHashTable(
142     FX_DWORD nHashSize, FX_BOOL bAllocNow)
143 {
144     ASSERT(m_nCount == 0);
145     ASSERT(nHashSize > 0);
146     if (m_pHashTable != NULL) {
147         FX_Free(m_pHashTable);
148         m_pHashTable = NULL;
149     }
150     if (bAllocNow) {
151         m_pHashTable = FX_Alloc(CAssoc*, nHashSize);
152     }
153     m_nHashTableSize = nHashSize;
154 }
155 FX_BOOL CFX_MapPtrToPtr::RemoveKey(void* key)
156 {
157     if (m_pHashTable == NULL) {
158         return FALSE;
159     }
160     CAssoc** ppAssocPrev;
161     ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
162     CAssoc* pAssoc;
163     for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext) {
164         if (pAssoc->key == key) {
165             *ppAssocPrev = pAssoc->pNext;
166             FreeAssoc(pAssoc);
167             return TRUE;
168         }
169         ppAssocPrev = &pAssoc->pNext;
170     }
171     return FALSE;
172 }
173 void CFX_MapPtrToPtr::FreeAssoc(CFX_MapPtrToPtr::CAssoc* pAssoc)
174 {
175     pAssoc->pNext = m_pFreeList;
176     m_pFreeList = pAssoc;
177     m_nCount--;
178     ASSERT(m_nCount >= 0);
179     if (m_nCount == 0) {
180         RemoveAll();
181     }
182 }
183 CFX_MapByteStringToPtr::CFX_MapByteStringToPtr(int nBlockSize)
184     : m_pHashTable(NULL)
185     , m_nHashTableSize(17)
186     , m_nCount(0)
187     , m_pFreeList(NULL)
188     , m_pBlocks(NULL)
189     , m_nBlockSize(nBlockSize)
190 {
191     ASSERT(m_nBlockSize > 0);
192 }
193 void CFX_MapByteStringToPtr::RemoveAll()
194 {
195     if (m_pHashTable != NULL) {
196         for (FX_DWORD nHash = 0; nHash < m_nHashTableSize; nHash++) {
197             CAssoc* pAssoc;
198             for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL;
199                     pAssoc = pAssoc->pNext) {
200                 DestructElement(&pAssoc->key);
201             }
202         }
203         FX_Free(m_pHashTable);
204         m_pHashTable = NULL;
205     }
206     m_nCount = 0;
207     m_pFreeList = NULL;
208     m_pBlocks->FreeDataChain();
209     m_pBlocks = NULL;
210 }
211 CFX_MapByteStringToPtr::~CFX_MapByteStringToPtr()
212 {
213     RemoveAll();
214     ASSERT(m_nCount == 0);
215 }
216 void CFX_MapByteStringToPtr::GetNextAssoc(FX_POSITION& rNextPosition,
217         CFX_ByteString& rKey, void*& rValue) const
218 {
219     ASSERT(m_pHashTable != NULL);
220     CAssoc* pAssocRet = (CAssoc*)rNextPosition;
221     ASSERT(pAssocRet != NULL);
222     if (pAssocRet == (CAssoc*) - 1) {
223         for (FX_DWORD nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
224             if ((pAssocRet = m_pHashTable[nBucket]) != NULL) {
225                 break;
226             }
227         ASSERT(pAssocRet != NULL);
228     }
229     CAssoc* pAssocNext;
230     if ((pAssocNext = pAssocRet->pNext) == NULL) {
231         for (FX_DWORD nBucket = pAssocRet->nHashValue + 1;
232                 nBucket < m_nHashTableSize; nBucket++)
233             if ((pAssocNext = m_pHashTable[nBucket]) != NULL) {
234                 break;
235             }
236     }
237     rNextPosition = (FX_POSITION) pAssocNext;
238     rKey = pAssocRet->key;
239     rValue = pAssocRet->value;
240 }
241 void* CFX_MapByteStringToPtr::GetNextValue(FX_POSITION& rNextPosition) const
242 {
243     ASSERT(m_pHashTable != NULL);
244     CAssoc* pAssocRet = (CAssoc*)rNextPosition;
245     ASSERT(pAssocRet != NULL);
246     if (pAssocRet == (CAssoc*) - 1) {
247         for (FX_DWORD nBucket = 0; nBucket < m_nHashTableSize; nBucket++)
248             if ((pAssocRet = m_pHashTable[nBucket]) != NULL) {
249                 break;
250             }
251         ASSERT(pAssocRet != NULL);
252     }
253     CAssoc* pAssocNext;
254     if ((pAssocNext = pAssocRet->pNext) == NULL) {
255         for (FX_DWORD nBucket = pAssocRet->nHashValue + 1;
256                 nBucket < m_nHashTableSize; nBucket++)
257             if ((pAssocNext = m_pHashTable[nBucket]) != NULL) {
258                 break;
259             }
260     }
261     rNextPosition = (FX_POSITION) pAssocNext;
262     return pAssocRet->value;
263 }
264 void*& CFX_MapByteStringToPtr::operator[](const CFX_ByteStringC& key)
265 {
266     FX_DWORD nHash;
267     CAssoc* pAssoc;
268     if ((pAssoc = GetAssocAt(key, nHash)) == NULL) {
269         if (m_pHashTable == NULL) {
270             InitHashTable(m_nHashTableSize);
271         }
272         pAssoc = NewAssoc();
273         pAssoc->nHashValue = nHash;
274         pAssoc->key = key;
275         pAssoc->pNext = m_pHashTable[nHash];
276         m_pHashTable[nHash] = pAssoc;
277     }
278     return pAssoc->value;
279 }
280 CFX_MapByteStringToPtr::CAssoc*
281 CFX_MapByteStringToPtr::NewAssoc()
282 {
283     if (m_pFreeList == NULL) {
284         CFX_Plex* newBlock = CFX_Plex::Create(m_pBlocks, m_nBlockSize, sizeof(CFX_MapByteStringToPtr::CAssoc));
285         CFX_MapByteStringToPtr::CAssoc* pAssoc = (CFX_MapByteStringToPtr::CAssoc*)newBlock->data();
286         pAssoc += m_nBlockSize - 1;
287         for (int i = m_nBlockSize - 1; i >= 0; i--, pAssoc--) {
288             pAssoc->pNext = m_pFreeList;
289             m_pFreeList = pAssoc;
290         }
291     }
292     ASSERT(m_pFreeList != NULL);
293     CFX_MapByteStringToPtr::CAssoc* pAssoc = m_pFreeList;
294     m_pFreeList = m_pFreeList->pNext;
295     m_nCount++;
296     ASSERT(m_nCount > 0);
297     ConstructElement(&pAssoc->key);
298     pAssoc->value = 0;
299     return pAssoc;
300 }
301 void CFX_MapByteStringToPtr::FreeAssoc(CFX_MapByteStringToPtr::CAssoc* pAssoc)
302 {
303     DestructElement(&pAssoc->key);
304     pAssoc->pNext = m_pFreeList;
305     m_pFreeList = pAssoc;
306     m_nCount--;
307     ASSERT(m_nCount >= 0);
308     if (m_nCount == 0) {
309         RemoveAll();
310     }
311 }
312 CFX_MapByteStringToPtr::CAssoc*
313 CFX_MapByteStringToPtr::GetAssocAt(const CFX_ByteStringC& key, FX_DWORD& nHash) const
314 {
315     nHash = HashKey(key) % m_nHashTableSize;
316     if (m_pHashTable == NULL) {
317         return NULL;
318     }
319     CAssoc* pAssoc;
320     for (pAssoc = m_pHashTable[nHash]; pAssoc != NULL; pAssoc = pAssoc->pNext) {
321         if (pAssoc->key == key) {
322             return pAssoc;
323         }
324     }
325     return NULL;
326 }
327 FX_BOOL CFX_MapByteStringToPtr::Lookup(const CFX_ByteStringC& key, void*& rValue) const
328 {
329     FX_DWORD nHash;
330     CAssoc* pAssoc = GetAssocAt(key, nHash);
331     if (pAssoc == NULL) {
332         return FALSE;
333     }
334     rValue = pAssoc->value;
335     return TRUE;
336 }
337 void CFX_MapByteStringToPtr::InitHashTable(
338     FX_DWORD nHashSize, FX_BOOL bAllocNow)
339 {
340     ASSERT(m_nCount == 0);
341     ASSERT(nHashSize > 0);
342     if (m_pHashTable != NULL) {
343         FX_Free(m_pHashTable);
344         m_pHashTable = NULL;
345     }
346     if (bAllocNow) {
347         m_pHashTable = FX_Alloc(CAssoc*, nHashSize);
348     }
349     m_nHashTableSize = nHashSize;
350 }
351 inline FX_DWORD CFX_MapByteStringToPtr::HashKey(const CFX_ByteStringC& key) const
352 {
353     FX_DWORD nHash = 0;
354     int len = key.GetLength();
355     const uint8_t* buf = key.GetPtr();
356     for (int i = 0; i < len; i ++) {
357         nHash = (nHash << 5) + nHash + buf[i];
358     }
359     return nHash;
360 }
361 FX_BOOL CFX_MapByteStringToPtr::RemoveKey(const CFX_ByteStringC& key)
362 {
363     if (m_pHashTable == NULL) {
364         return FALSE;
365     }
366     CAssoc** ppAssocPrev;
367     ppAssocPrev = &m_pHashTable[HashKey(key) % m_nHashTableSize];
368     CAssoc* pAssoc;
369     for (pAssoc = *ppAssocPrev; pAssoc != NULL; pAssoc = pAssoc->pNext) {
370         if (pAssoc->key == key) {
371             *ppAssocPrev = pAssoc->pNext;
372             FreeAssoc(pAssoc);
373             return TRUE;
374         }
375         ppAssocPrev = &pAssoc->pNext;
376     }
377     return FALSE;
378 }
379 struct _CompactString {
380     uint8_t             m_CompactLen;
381     uint8_t             m_LenHigh;
382     uint8_t             m_LenLow;
383     uint8_t             m_Unused;
384     uint8_t*    m_pBuffer;
385 };
386 static void _CompactStringRelease(_CompactString* pCompact)
387 {
388     if (pCompact->m_CompactLen == 0xff) {
389         FX_Free(pCompact->m_pBuffer);
390     }
391 }
392 static FX_BOOL _CompactStringSame(_CompactString* pCompact, const uint8_t* pStr, int len)
393 {
394     if (len < sizeof(_CompactString)) {
395         if (pCompact->m_CompactLen != len) {
396             return FALSE;
397         }
398         return FXSYS_memcmp(&pCompact->m_LenHigh, pStr, len) == 0;
399     }
400     if (pCompact->m_CompactLen != 0xff || pCompact->m_LenHigh * 256 + pCompact->m_LenLow != len) {
401         return FALSE;
402     }
403     return FXSYS_memcmp(pCompact->m_pBuffer, pStr, len) == 0;
404 }
405 static void _CompactStringStore(_CompactString* pCompact, const uint8_t* pStr, int len)
406 {
407     if (len < (int)sizeof(_CompactString)) {
408         pCompact->m_CompactLen = (uint8_t)len;
409         FXSYS_memcpy(&pCompact->m_LenHigh, pStr, len);
410         return;
411     }
412     pCompact->m_CompactLen = 0xff;
413     pCompact->m_LenHigh = len / 256;
414     pCompact->m_LenLow = len % 256;
415     pCompact->m_pBuffer = FX_Alloc(uint8_t, len);
416     FXSYS_memcpy(pCompact->m_pBuffer, pStr, len);
417 }
418 static CFX_ByteStringC _CompactStringGet(_CompactString* pCompact)
419 {
420     if (pCompact->m_CompactLen == 0xff) {
421         return CFX_ByteStringC(pCompact->m_pBuffer, pCompact->m_LenHigh * 256 + pCompact->m_LenLow);
422     }
423     if (pCompact->m_CompactLen == 0xfe) {
424         return CFX_ByteStringC();
425     }
426     return CFX_ByteStringC(&pCompact->m_LenHigh, pCompact->m_CompactLen);
427 }
428 #define CMAP_ALLOC_STEP         8
429 #define CMAP_INDEX_SIZE         8
430 CFX_CMapByteStringToPtr::CFX_CMapByteStringToPtr()
431     : m_Buffer(sizeof(_CompactString) + sizeof(void*), CMAP_ALLOC_STEP, CMAP_INDEX_SIZE)
432 {
433 }
434 CFX_CMapByteStringToPtr::~CFX_CMapByteStringToPtr()
435 {
436     RemoveAll();
437 }
438 void CFX_CMapByteStringToPtr::RemoveAll()
439 {
440     int size = m_Buffer.GetSize();
441     for (int i = 0; i < size; i++) {
442         _CompactStringRelease((_CompactString*)m_Buffer.GetAt(i));
443     }
444     m_Buffer.RemoveAll();
445 }
446 FX_POSITION CFX_CMapByteStringToPtr::GetStartPosition() const
447 {
448     int size = m_Buffer.GetSize();
449     for (int i = 0; i < size; i ++) {
450         _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(i);
451         if (pKey->m_CompactLen != 0xfe) {
452             return (FX_POSITION)(uintptr_t)(i + 1);
453         }
454     }
455     return NULL;
456 }
457 void CFX_CMapByteStringToPtr::GetNextAssoc(FX_POSITION& rNextPosition, CFX_ByteString& rKey, void*& rValue) const
458 {
459     if (rNextPosition == NULL) {
460         return;
461     }
462     int index = (int)(uintptr_t)rNextPosition - 1;
463     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
464     rKey = _CompactStringGet(pKey);
465     rValue = *(void**)(pKey + 1);
466     index ++;
467     int size = m_Buffer.GetSize();
468     while (index < size) {
469         pKey = (_CompactString*)m_Buffer.GetAt(index);
470         if (pKey->m_CompactLen != 0xfe) {
471             rNextPosition = (FX_POSITION)(uintptr_t)(index + 1);
472             return;
473         }
474         index ++;
475     }
476     rNextPosition = NULL;
477 }
478 void* CFX_CMapByteStringToPtr::GetNextValue(FX_POSITION& rNextPosition) const
479 {
480     if (rNextPosition == NULL) {
481         return NULL;
482     }
483     int index = (int)(uintptr_t)rNextPosition - 1;
484     _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
485     void* rValue = *(void**)(pKey + 1);
486     index ++;
487     int size = m_Buffer.GetSize();
488     while (index < size) {
489         pKey = (_CompactString*)m_Buffer.GetAt(index);
490         if (pKey->m_CompactLen != 0xfe) {
491             rNextPosition = (FX_POSITION)(uintptr_t)(index + 1);
492             return rValue;
493         }
494         index ++;
495     }
496     rNextPosition = NULL;
497     return rValue;
498 }
499 FX_BOOL _CMapLookupCallback(void* param, void* pData)
500 {
501     return !_CompactStringSame((_CompactString*)pData, ((CFX_ByteStringC*)param)->GetPtr(), ((CFX_ByteStringC*)param)->GetLength());
502 }
503 FX_BOOL CFX_CMapByteStringToPtr::Lookup(const CFX_ByteStringC& key, void*& rValue) const
504 {
505     void* p = m_Buffer.Iterate(_CMapLookupCallback, (void*)&key);
506     if (!p) {
507         return FALSE;
508     }
509     rValue = *(void**)((_CompactString*)p + 1);
510     return TRUE;
511 }
512 void CFX_CMapByteStringToPtr::SetAt(const CFX_ByteStringC& key, void* value)
513 {
514     ASSERT(value != NULL);
515     int index, key_len = key.GetLength();
516     int size = m_Buffer.GetSize();
517     for (index = 0; index < size; index ++) {
518         _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
519         if (!_CompactStringSame(pKey, key.GetPtr(), key_len)) {
520             continue;
521         }
522         *(void**)(pKey + 1) = value;
523         return;
524     }
525     for (index = 0; index < size; index ++) {
526         _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
527         if (pKey->m_CompactLen) {
528             continue;
529         }
530         _CompactStringStore(pKey, key.GetPtr(), key_len);
531         *(void**)(pKey + 1) = value;
532         return;
533     }
534     _CompactString* pKey = (_CompactString*)m_Buffer.Add();
535     _CompactStringStore(pKey, key.GetPtr(), key_len);
536     *(void**)(pKey + 1) = value;
537 }
538 void CFX_CMapByteStringToPtr::AddValue(const CFX_ByteStringC& key, void* value)
539 {
540     ASSERT(value != NULL);
541     _CompactString* pKey = (_CompactString*)m_Buffer.Add();
542     _CompactStringStore(pKey, key.GetPtr(), key.GetLength());
543     *(void**)(pKey + 1) = value;
544 }
545 void CFX_CMapByteStringToPtr::RemoveKey(const CFX_ByteStringC& key)
546 {
547     int key_len = key.GetLength();
548     int size = m_Buffer.GetSize();
549     for (int index = 0; index < size; index++) {
550         _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(index);
551         if (!_CompactStringSame(pKey, key.GetPtr(), key_len)) {
552             continue;
553         }
554         _CompactStringRelease(pKey);
555         pKey->m_CompactLen = 0xfe;
556         return;
557     }
558 }
559 int CFX_CMapByteStringToPtr::GetCount() const
560 {
561     int count = 0;
562     int size = m_Buffer.GetSize();
563     for (int i = 0; i < size; i ++) {
564         _CompactString* pKey = (_CompactString*)m_Buffer.GetAt(i);
565         if (pKey->m_CompactLen != 0xfe) {
566             count ++;
567         }
568     }
569     return count;
570 }
571 extern "C" {
572     static int _CompareDWord(const void* p1, const void* p2)
573     {
574         return (*(FX_DWORD*)p1) - (*(FX_DWORD*)p2);
575     }
576 };
577 struct _DWordPair {
578     FX_DWORD key;
579     FX_DWORD value;
580 };
581 FX_BOOL CFX_CMapDWordToDWord::Lookup(FX_DWORD key, FX_DWORD& value) const
582 {
583     void* pResult = FXSYS_bsearch(&key, m_Buffer.GetBuffer(), m_Buffer.GetSize() / sizeof(_DWordPair),
584                                       sizeof(_DWordPair), _CompareDWord);
585     if (pResult == NULL) {
586         return FALSE;
587     }
588     value = ((FX_DWORD*)pResult)[1];
589     return TRUE;
590 }
591 FX_POSITION CFX_CMapDWordToDWord::GetStartPosition() const
592 {
593     FX_DWORD count = m_Buffer.GetSize() / sizeof(_DWordPair);
594     if (count == 0) {
595         return NULL;
596     }
597     return (FX_POSITION)1;
598 }
599 void CFX_CMapDWordToDWord::GetNextAssoc(FX_POSITION& pos, FX_DWORD& key, FX_DWORD& value) const
600 {
601     if (pos == 0) {
602         return;
603     }
604     FX_DWORD index = ((FX_DWORD)(uintptr_t)pos) - 1;
605     FX_DWORD count = m_Buffer.GetSize() / sizeof(_DWordPair);
606     _DWordPair* buf = (_DWordPair*)m_Buffer.GetBuffer();
607     key = buf[index].key;
608     value = buf[index].value;
609     if (index == count - 1) {
610         pos = 0;
611     } else {
612         pos = (FX_POSITION)((uintptr_t)pos + 1);
613     }
614 }
615 void CFX_CMapDWordToDWord::SetAt(FX_DWORD key, FX_DWORD value)
616 {
617     FX_DWORD count = m_Buffer.GetSize() / sizeof(_DWordPair);
618     _DWordPair* buf = (_DWordPair*)m_Buffer.GetBuffer();
619     _DWordPair pair = {key, value};
620     if (count == 0 || key > buf[count - 1].key) {
621         m_Buffer.AppendBlock(&pair, sizeof(_DWordPair));
622         return;
623     }
624     int low = 0, high = count - 1;
625     while (low <= high) {
626         int mid = (low + high) / 2;
627         if (buf[mid].key < key) {
628             low = mid + 1;
629         } else if (buf[mid].key > key) {
630             high = mid - 1;
631         } else {
632             buf[mid].value = value;
633             return;
634         }
635     }
636     m_Buffer.InsertBlock(low * sizeof(_DWordPair), &pair, sizeof(_DWordPair));
637 }
638 void CFX_CMapDWordToDWord::EstimateSize(FX_DWORD size, FX_DWORD grow_by)
639 {
640     m_Buffer.EstimateSize(size, grow_by);
641 }