| /* Copyright (C) 2021-2024 Free Software Foundation, Inc. | |
| Contributed by Oracle. | |
| This file is part of GNU Binutils. | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 3, or (at your option) | |
| any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, 51 Franklin Street - Fifth Floor, Boston, | |
| MA 02110-1301, USA. */ | |
| /* | |
| * Cache Map implementation. | |
| * | |
| * Cache Map makes the following assumptions: | |
| * - Cache Map is used for very fast but not guaranteed mapping; | |
| * - only REL_EQ Relation can be used; | |
| * - all objects used as keys or values has to be managed | |
| * outside CacheMap (f.e. deletion); | |
| * - (Key_t)0 is invalid key; | |
| * - (Value_t)0 is invalid value; | |
| * - <TBC> | |
| */ | |
| #ifndef _DBE_CACHEMAP_H | |
| #define _DBE_CACHEMAP_H | |
| #include <assert.h> | |
| #include <vec.h> | |
| #include <Map.h> | |
| template <typename Key_t, typename Value_t> | |
| class CacheMap : public Map<Key_t, Value_t> | |
| { | |
| public: | |
| CacheMap (); | |
| ~CacheMap (); | |
| void put (Key_t key, Value_t val); | |
| Value_t get (Key_t key); | |
| Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel); | |
| Value_t | |
| remove (Key_t key); | |
| private: | |
| struct Entry | |
| { | |
| Key_t key; | |
| Value_t val; | |
| Entry () | |
| { | |
| key = (Key_t) 0; | |
| } | |
| }; | |
| static const int INIT_SIZE; | |
| static const int MAX_SIZE; | |
| static unsigned hash (Key_t key); | |
| Entry *getEntry (Key_t key); | |
| int cursize; | |
| int nputs; | |
| int nchunks; | |
| Entry **chunks; | |
| }; | |
| template <typename Key_t, typename Value_t> | |
| const int CacheMap<Key_t, Value_t>::INIT_SIZE = 1 << 14; | |
| template <typename Key_t, typename Value_t> | |
| const int CacheMap<Key_t, Value_t>::MAX_SIZE = 1 << 20; | |
| template <typename Key_t, typename Value_t>CacheMap<Key_t, Value_t> | |
| ::CacheMap () | |
| { | |
| cursize = INIT_SIZE; | |
| chunks = new Entry*[32]; | |
| nchunks = 0; | |
| chunks[nchunks++] = new Entry[cursize]; | |
| nputs = 0; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| CacheMap<Key_t, Value_t>::~CacheMap () | |
| { | |
| for (int i = 0; i < nchunks; i++) | |
| delete[] chunks[i]; | |
| delete[] chunks; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| unsigned | |
| CacheMap<Key_t, Value_t>::hash (Key_t key) | |
| { | |
| unsigned h = (unsigned) key ^ (unsigned) (key >> 32); | |
| h ^= (h >> 20) ^ (h >> 12); | |
| return h ^ (h >> 7) ^ (h >> 4); | |
| } | |
| template <typename Key_t, typename Value_t> | |
| void | |
| CacheMap<Key_t, Value_t>::put (Key_t key, Value_t val) | |
| { | |
| if (nputs >= cursize && cursize < MAX_SIZE) | |
| { | |
| // Allocate new chunk for entries. | |
| chunks[nchunks++] = new Entry[cursize]; | |
| cursize *= 2; | |
| // Copy all old entries to the newly allocated chunk | |
| Entry *newchunk = chunks[nchunks - 1]; | |
| int prevsz = 0; | |
| int nextsz = INIT_SIZE; | |
| for (int i = 0; i < nchunks - 1; i++) | |
| { | |
| Entry *oldchunk = chunks[i]; | |
| for (int j = prevsz; j < nextsz; j++) | |
| newchunk[j] = oldchunk[j - prevsz]; | |
| prevsz = nextsz; | |
| nextsz *= 2; | |
| } | |
| } | |
| Entry *entry = getEntry (key); | |
| entry->key = key; | |
| entry->val = val; | |
| nputs++; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| typename CacheMap<Key_t, Value_t>::Entry * | |
| CacheMap<Key_t, Value_t>::getEntry (Key_t key) | |
| { | |
| unsigned idx = hash (key); | |
| int i = nchunks - 1; | |
| int j = cursize / 2; | |
| for (; i > 0; i -= 1, j /= 2) | |
| if (idx & j) | |
| break; | |
| if (i == 0) | |
| j *= 2; | |
| return &chunks[i][idx & (j - 1)]; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| CacheMap<Key_t, Value_t>::get (Key_t key) | |
| { | |
| Entry *entry = getEntry (key); | |
| return entry->key == key ? entry->val : (Value_t) 0; | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| CacheMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel) | |
| { | |
| if (rel != Map<Key_t, Value_t>::REL_EQ) | |
| return (Value_t) 0; | |
| return get (key); | |
| } | |
| template <typename Key_t, typename Value_t> | |
| Value_t | |
| CacheMap<Key_t, Value_t>::remove (Key_t key) | |
| { | |
| Entry *entry = getEntry (key); | |
| Value_t res = (Value_t) 0; | |
| if (entry->key == key) | |
| { | |
| res = entry->val; | |
| entry->val = (Value_t) 0; | |
| } | |
| return res; | |
| } | |
| #endif |