xref: /netbsd-src/external/gpl3/binutils/dist/gprofng/src/CacheMap.h (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
1*cb63e24eSchristos /* Copyright (C) 2021-2024 Free Software Foundation, Inc.
24f645668Schristos    Contributed by Oracle.
34f645668Schristos 
44f645668Schristos    This file is part of GNU Binutils.
54f645668Schristos 
64f645668Schristos    This program is free software; you can redistribute it and/or modify
74f645668Schristos    it under the terms of the GNU General Public License as published by
84f645668Schristos    the Free Software Foundation; either version 3, or (at your option)
94f645668Schristos    any later version.
104f645668Schristos 
114f645668Schristos    This program is distributed in the hope that it will be useful,
124f645668Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
134f645668Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
144f645668Schristos    GNU General Public License for more details.
154f645668Schristos 
164f645668Schristos    You should have received a copy of the GNU General Public License
174f645668Schristos    along with this program; if not, write to the Free Software
184f645668Schristos    Foundation, 51 Franklin Street - Fifth Floor, Boston,
194f645668Schristos    MA 02110-1301, USA.  */
204f645668Schristos 
214f645668Schristos /*
224f645668Schristos  *  Cache Map implementation.
234f645668Schristos  *
244f645668Schristos  *  Cache Map makes the following assumptions:
254f645668Schristos  *    - Cache Map is used for very fast but not guaranteed mapping;
264f645668Schristos  *    - only REL_EQ Relation can be used;
274f645668Schristos  *    - all objects used as keys or values has to be managed
284f645668Schristos  *      outside CacheMap (f.e. deletion);
294f645668Schristos  *    - (Key_t)0 is invalid key;
304f645668Schristos  *    - (Value_t)0 is invalid value;
314f645668Schristos  *    - <TBC>
324f645668Schristos  */
334f645668Schristos 
344f645668Schristos #ifndef _DBE_CACHEMAP_H
354f645668Schristos #define _DBE_CACHEMAP_H
364f645668Schristos 
374f645668Schristos #include <assert.h>
384f645668Schristos #include <vec.h>
394f645668Schristos #include <Map.h>
404f645668Schristos 
414f645668Schristos template <typename Key_t, typename Value_t>
424f645668Schristos class CacheMap : public Map<Key_t, Value_t>
434f645668Schristos {
444f645668Schristos public:
454f645668Schristos 
464f645668Schristos   CacheMap ();
474f645668Schristos   ~CacheMap ();
484f645668Schristos   void put (Key_t key, Value_t val);
494f645668Schristos   Value_t get (Key_t key);
504f645668Schristos   Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
514f645668Schristos   Value_t
524f645668Schristos   remove (Key_t key);
534f645668Schristos 
544f645668Schristos private:
554f645668Schristos 
564f645668Schristos   struct Entry
574f645668Schristos   {
584f645668Schristos     Key_t key;
594f645668Schristos     Value_t val;
604f645668Schristos 
EntryEntry614f645668Schristos     Entry ()
624f645668Schristos     {
634f645668Schristos       key = (Key_t) 0;
644f645668Schristos     }
654f645668Schristos   };
664f645668Schristos 
674f645668Schristos   static const int INIT_SIZE;
684f645668Schristos   static const int MAX_SIZE;
694f645668Schristos 
704f645668Schristos   static unsigned hash (Key_t key);
714f645668Schristos   Entry *getEntry (Key_t key);
724f645668Schristos 
734f645668Schristos   int cursize;
744f645668Schristos   int nputs;
754f645668Schristos   int nchunks;
764f645668Schristos   Entry **chunks;
774f645668Schristos };
784f645668Schristos 
794f645668Schristos template <typename Key_t, typename Value_t>
804f645668Schristos const int CacheMap<Key_t, Value_t>::INIT_SIZE = 1 << 14;
814f645668Schristos template <typename Key_t, typename Value_t>
824f645668Schristos const int CacheMap<Key_t, Value_t>::MAX_SIZE = 1 << 20;
834f645668Schristos 
844f645668Schristos template <typename Key_t, typename Value_t>CacheMap<Key_t, Value_t>
CacheMap()854f645668Schristos ::CacheMap ()
864f645668Schristos {
874f645668Schristos   cursize = INIT_SIZE;
884f645668Schristos   chunks = new Entry*[32];
894f645668Schristos   nchunks = 0;
904f645668Schristos   chunks[nchunks++] = new Entry[cursize];
914f645668Schristos   nputs = 0;
924f645668Schristos }
934f645668Schristos 
944f645668Schristos template <typename Key_t, typename Value_t>
~CacheMap()954f645668Schristos CacheMap<Key_t, Value_t>::~CacheMap ()
964f645668Schristos {
974f645668Schristos   for (int i = 0; i < nchunks; i++)
984f645668Schristos     delete[] chunks[i];
994f645668Schristos   delete[] chunks;
1004f645668Schristos }
1014f645668Schristos 
1024f645668Schristos template <typename Key_t, typename Value_t>
1034f645668Schristos unsigned
hash(Key_t key)1044f645668Schristos CacheMap<Key_t, Value_t>::hash (Key_t key)
1054f645668Schristos {
1064f645668Schristos   unsigned h = (unsigned) key ^ (unsigned) (key >> 32);
1074f645668Schristos   h ^= (h >> 20) ^ (h >> 12);
1084f645668Schristos   return h ^ (h >> 7) ^ (h >> 4);
1094f645668Schristos }
1104f645668Schristos 
1114f645668Schristos template <typename Key_t, typename Value_t>
1124f645668Schristos void
put(Key_t key,Value_t val)1134f645668Schristos CacheMap<Key_t, Value_t>::put (Key_t key, Value_t val)
1144f645668Schristos {
1154f645668Schristos   if (nputs >= cursize && cursize < MAX_SIZE)
1164f645668Schristos     {
1174f645668Schristos       // Allocate new chunk for entries.
1184f645668Schristos       chunks[nchunks++] = new Entry[cursize];
1194f645668Schristos       cursize *= 2;
1204f645668Schristos 
1214f645668Schristos       // Copy all old entries to the newly allocated chunk
1224f645668Schristos       Entry *newchunk = chunks[nchunks - 1];
1234f645668Schristos       int prevsz = 0;
1244f645668Schristos       int nextsz = INIT_SIZE;
1254f645668Schristos       for (int i = 0; i < nchunks - 1; i++)
1264f645668Schristos 	{
1274f645668Schristos 	  Entry *oldchunk = chunks[i];
1284f645668Schristos 	  for (int j = prevsz; j < nextsz; j++)
1294f645668Schristos 	    newchunk[j] = oldchunk[j - prevsz];
1304f645668Schristos 	  prevsz = nextsz;
1314f645668Schristos 	  nextsz *= 2;
1324f645668Schristos 	}
1334f645668Schristos     }
1344f645668Schristos   Entry *entry = getEntry (key);
1354f645668Schristos   entry->key = key;
1364f645668Schristos   entry->val = val;
1374f645668Schristos   nputs++;
1384f645668Schristos }
1394f645668Schristos 
1404f645668Schristos template <typename Key_t, typename Value_t>
1414f645668Schristos typename CacheMap<Key_t, Value_t>::Entry *
getEntry(Key_t key)1424f645668Schristos CacheMap<Key_t, Value_t>::getEntry (Key_t key)
1434f645668Schristos {
1444f645668Schristos   unsigned idx = hash (key);
1454f645668Schristos   int i = nchunks - 1;
1464f645668Schristos   int j = cursize / 2;
1474f645668Schristos   for (; i > 0; i -= 1, j /= 2)
1484f645668Schristos     if (idx & j)
1494f645668Schristos       break;
1504f645668Schristos   if (i == 0)
1514f645668Schristos     j *= 2;
1524f645668Schristos   return &chunks[i][idx & (j - 1)];
1534f645668Schristos }
1544f645668Schristos 
1554f645668Schristos template <typename Key_t, typename Value_t>
1564f645668Schristos Value_t
get(Key_t key)1574f645668Schristos CacheMap<Key_t, Value_t>::get (Key_t key)
1584f645668Schristos {
1594f645668Schristos   Entry *entry = getEntry (key);
1604f645668Schristos   return entry->key == key ? entry->val : (Value_t) 0;
1614f645668Schristos }
1624f645668Schristos 
1634f645668Schristos template <typename Key_t, typename Value_t>
1644f645668Schristos Value_t
get(Key_t key,typename Map<Key_t,Value_t>::Relation rel)1654f645668Schristos CacheMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
1664f645668Schristos {
1674f645668Schristos   if (rel != Map<Key_t, Value_t>::REL_EQ)
1684f645668Schristos     return (Value_t) 0;
1694f645668Schristos   return get (key);
1704f645668Schristos }
1714f645668Schristos 
1724f645668Schristos template <typename Key_t, typename Value_t>
1734f645668Schristos Value_t
remove(Key_t key)1744f645668Schristos CacheMap<Key_t, Value_t>::remove (Key_t key)
1754f645668Schristos {
1764f645668Schristos   Entry *entry = getEntry (key);
1774f645668Schristos   Value_t res = (Value_t) 0;
1784f645668Schristos   if (entry->key == key)
1794f645668Schristos     {
1804f645668Schristos       res = entry->val;
1814f645668Schristos       entry->val = (Value_t) 0;
1824f645668Schristos     }
1834f645668Schristos   return res;
1844f645668Schristos }
1854f645668Schristos 
1864f645668Schristos #endif
187