| /* 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 |