| 1 | /* A type-safe hash map. | 
| 2 |    Copyright (C) 2014-2025 Free Software Foundation, Inc. | 
| 3 |  | 
| 4 | This file is part of GCC. | 
| 5 |  | 
| 6 | GCC is free software; you can redistribute it and/or modify it under | 
| 7 | the terms of the GNU General Public License as published by the Free | 
| 8 | Software Foundation; either version 3, or (at your option) any later | 
| 9 | version. | 
| 10 |  | 
| 11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY | 
| 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
| 13 | FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
| 14 | for more details. | 
| 15 |  | 
| 16 | You should have received a copy of the GNU General Public License | 
| 17 | along with GCC; see the file COPYING3.  If not see | 
| 18 | <http://www.gnu.org/licenses/>.  */ | 
| 19 |  | 
| 20 |  | 
| 21 | #ifndef hash_map_h | 
| 22 | #define hash_map_h | 
| 23 |  | 
| 24 | /* Class hash_map is a hash-value based container mapping objects of | 
| 25 |    KeyId type to those of the Value type. | 
| 26 |    Both KeyId and Value may be non-trivial (non-POD) types provided | 
| 27 |    a suitabe Traits class.  A few default Traits specializations are | 
| 28 |    provided for basic types such as integers, pointers, and std::pair. | 
| 29 |    Inserted elements are value-initialized either to zero for POD types | 
| 30 |    or by invoking their default ctor.  Removed elements are destroyed | 
| 31 |    by invoking their dtor.   On hash_map destruction all elements are | 
| 32 |    removed.  Objects of hash_map type are copy-constructible but not | 
| 33 |    assignable.  */ | 
| 34 |  | 
| 35 | const size_t default_hash_map_size = 13; | 
| 36 | template<typename KeyId, typename Value, | 
| 37 |          typename Traits /* = simple_hashmap_traits<default_hash_traits<Key>, | 
| 38 |                                                     Value> */> | 
| 39 | class GTY((user)) hash_map | 
| 40 | { | 
| 41 |   typedef typename Traits::key_type Key; | 
| 42 |   struct hash_entry | 
| 43 |   { | 
| 44 |     Key m_key; | 
| 45 |     Value m_value; | 
| 46 |  | 
| 47 |     typedef hash_entry value_type; | 
| 48 |     typedef Key compare_type; | 
| 49 |  | 
| 50 |     static hashval_t hash (const hash_entry &e) | 
| 51 |       { | 
| 52 |                return Traits::hash (e.m_key); | 
| 53 |       } | 
| 54 |  | 
| 55 |     static bool equal (const hash_entry &a, const Key &b) | 
| 56 |                { | 
| 57 |           return Traits::equal_keys (a.m_key, b); | 
| 58 |                } | 
| 59 |  | 
| 60 |     static void remove (hash_entry &e) { Traits::remove (e); } | 
| 61 |  | 
| 62 |     static void mark_deleted (hash_entry &e) { Traits::mark_deleted (e); } | 
| 63 |  | 
| 64 |     static bool is_deleted (const hash_entry &e) | 
| 65 |       { | 
| 66 |                return Traits::is_deleted (e); | 
| 67 |       } | 
| 68 |  | 
| 69 |     static const bool empty_zero_p = Traits::empty_zero_p; | 
| 70 |     static void mark_empty (hash_entry &e) { Traits::mark_empty (e); } | 
| 71 |     static bool is_empty (const hash_entry &e) { return Traits::is_empty (e); } | 
| 72 |  | 
| 73 |     static void ggc_mx (hash_entry &e) | 
| 74 |       { | 
| 75 |         gt_ggc_mx (e.m_key); | 
| 76 |         gt_ggc_mx (e.m_value); | 
| 77 |       } | 
| 78 |  | 
| 79 |     static void ggc_maybe_mx (hash_entry &e) | 
| 80 |       { | 
| 81 |         if (Traits::maybe_mx) | 
| 82 |           ggc_mx (e); | 
| 83 |       } | 
| 84 |  | 
| 85 |     static void pch_nx (hash_entry &e) | 
| 86 |       { | 
| 87 |         gt_pch_nx (e.m_key); | 
| 88 |         gt_pch_nx (e.m_value); | 
| 89 |       } | 
| 90 |  | 
| 91 |     static void pch_nx (hash_entry &e, gt_pointer_operator op, void *c) | 
| 92 |       { | 
| 93 |         pch_nx_helper (e.m_key, op, c); | 
| 94 |         pch_nx_helper (e.m_value, op, c); | 
| 95 |       } | 
| 96 |  | 
| 97 |     static int keep_cache_entry (hash_entry &e) | 
| 98 |       { | 
| 99 |         return ggc_marked_p (e.m_key); | 
| 100 |       } | 
| 101 |  | 
| 102 |   private: | 
| 103 |     template<typename T> | 
| 104 |     static void | 
| 105 |       pch_nx_helper (T &x, gt_pointer_operator op, void *cookie) | 
| 106 |         { | 
| 107 |           gt_pch_nx (&x, op, cookie); | 
| 108 |         } | 
| 109 |  | 
| 110 |     template<typename T> | 
| 111 |       static void | 
| 112 |       pch_nx_helper (T *&x, gt_pointer_operator op, void *cookie) | 
| 113 |         { | 
| 114 |           op (&x, NULL, cookie); | 
| 115 |         } | 
| 116 |  | 
| 117 |     /* The overloads below should match those in ggc.h.  */ | 
| 118 | #define DEFINE_PCH_HELPER(T)                        \ | 
| 119 |     static void pch_nx_helper (T, gt_pointer_operator, void *) { } | 
| 120 |  | 
| 121 |     DEFINE_PCH_HELPER (bool); | 
| 122 |     DEFINE_PCH_HELPER (char); | 
| 123 |     DEFINE_PCH_HELPER (signed char); | 
| 124 |     DEFINE_PCH_HELPER (unsigned char); | 
| 125 |     DEFINE_PCH_HELPER (short); | 
| 126 |     DEFINE_PCH_HELPER (unsigned short); | 
| 127 |     DEFINE_PCH_HELPER (int); | 
| 128 |     DEFINE_PCH_HELPER (unsigned int); | 
| 129 |     DEFINE_PCH_HELPER (long); | 
| 130 |     DEFINE_PCH_HELPER (unsigned long); | 
| 131 |     DEFINE_PCH_HELPER (long long); | 
| 132 |     DEFINE_PCH_HELPER (unsigned long long); | 
| 133 |  | 
| 134 | #undef DEFINE_PCH_HELPER | 
| 135 |   }; | 
| 136 |  | 
| 137 | public: | 
| 138 |   explicit hash_map (size_t n = default_hash_map_size, bool ggc = false, | 
| 139 |                      bool sanitize_eq_and_hash = true, | 
| 140 |                      bool gather_mem_stats = GATHER_STATISTICS | 
| 141 |                      CXX_MEM_STAT_INFO) | 
| 142 |     : m_table (n, ggc, sanitize_eq_and_hash, gather_mem_stats, | 
| 143 |                HASH_MAP_ORIGIN PASS_MEM_STAT) | 
| 144 |   { | 
| 145 |   } | 
| 146 |  | 
| 147 |   explicit hash_map (const hash_map &h, bool ggc = false, | 
| 148 |                      bool sanitize_eq_and_hash = true, | 
| 149 |                      bool gather_mem_stats = GATHER_STATISTICS | 
| 150 |                      CXX_MEM_STAT_INFO) | 
| 151 |     : m_table (h.m_table, ggc, sanitize_eq_and_hash, gather_mem_stats, | 
| 152 |                HASH_MAP_ORIGIN PASS_MEM_STAT) {} | 
| 153 |  | 
| 154 |   /* Create a hash_map in ggc memory.  */ | 
| 155 |   static hash_map *create_ggc (size_t size = default_hash_map_size, | 
| 156 |                                bool gather_mem_stats = GATHER_STATISTICS | 
| 157 |                                CXX_MEM_STAT_INFO) | 
| 158 |     { | 
| 159 |       hash_map *map = ggc_alloc<hash_map> (); | 
| 160 |       new (map) hash_map (size, true, true, gather_mem_stats PASS_MEM_STAT); | 
| 161 |       return map; | 
| 162 |     } | 
| 163 |  | 
| 164 |   /* If key k isn't already in the map add key k with value v to the map, and | 
| 165 |      return false.  Otherwise set the value of the entry for key k to be v and | 
| 166 |      return true.  */ | 
| 167 |  | 
| 168 |   bool put (const Key &k, const Value &v) | 
| 169 |     { | 
| 170 |       hash_entry *e = m_table.find_slot_with_hash (k, Traits::hash (k), | 
| 171 |                                                    INSERT); | 
| 172 |       bool ins = Traits::is_empty (*e); | 
| 173 |       if (ins) | 
| 174 |         { | 
| 175 |           e->m_key = k; | 
| 176 |           new ((void *)&e->m_value) Value (v); | 
| 177 |           gcc_checking_assert (!Traits::is_empty (*e) | 
| 178 |                                && !Traits::is_deleted (*e)); | 
| 179 |         } | 
| 180 |       else | 
| 181 |         e->m_value = v; | 
| 182 |  | 
| 183 |       return !ins; | 
| 184 |     } | 
| 185 |  | 
| 186 |   /* If the passed in key is in the map return pointer to its value | 
| 187 |      otherwise NULL.  */ | 
| 188 |  | 
| 189 |   Value *get (const Key &k) | 
| 190 |     { | 
| 191 |       hash_entry &e = m_table.find_with_hash (k, Traits::hash (k)); | 
| 192 |       return Traits::is_empty (e) ? NULL : &e.m_value; | 
| 193 |     } | 
| 194 |  | 
| 195 |   /* Return a reference to the value for the passed in key, creating the entry | 
| 196 |      if it doesn't already exist.  If existed is not NULL then it is set to | 
| 197 |      false if the key was not previously in the map, and true otherwise.  */ | 
| 198 |  | 
| 199 |   Value &get_or_insert (const Key &k, bool *existed = NULL) | 
| 200 |     { | 
| 201 |       hash_entry *e = m_table.find_slot_with_hash (k, Traits::hash (k), | 
| 202 |                                                    INSERT); | 
| 203 |       bool ins = Traits::is_empty (*e); | 
| 204 |       if (ins) | 
| 205 |         { | 
| 206 |           e->m_key = k; | 
| 207 |           new ((void *)&e->m_value) Value (); | 
| 208 |           gcc_checking_assert (!Traits::is_empty (*e) | 
| 209 |                                && !Traits::is_deleted (*e)); | 
| 210 |         } | 
| 211 |  | 
| 212 |       if (existed != NULL) | 
| 213 |         *existed = !ins; | 
| 214 |  | 
| 215 |       return e->m_value; | 
| 216 |     } | 
| 217 |  | 
| 218 |   void remove (const Key &k) | 
| 219 |     { | 
| 220 |       m_table.remove_elt_with_hash (k, Traits::hash (k)); | 
| 221 |     } | 
| 222 |  | 
| 223 |   /* Call the call back on each pair of key and value with the passed in | 
| 224 |      arg until either the call back returns false or all pairs have been seen. | 
| 225 |      The traversal is unordered.  */ | 
| 226 |  | 
| 227 |   template<typename Arg, bool (*f)(const typename Traits::key_type &, | 
| 228 |                                    const Value &, Arg)> | 
| 229 |   void traverse (Arg a) const | 
| 230 |     { | 
| 231 |       for (typename hash_table<hash_entry>::iterator iter = m_table.begin (); | 
| 232 |            iter != m_table.end (); ++iter) | 
| 233 |         if (!f ((*iter).m_key, (*iter).m_value, a)) | 
| 234 |           break; | 
| 235 |     } | 
| 236 |  | 
| 237 |   template<typename Arg, bool (*f)(const typename Traits::key_type &, | 
| 238 |                                    Value *, Arg)> | 
| 239 |   void traverse (Arg a) const | 
| 240 |     { | 
| 241 |       for (typename hash_table<hash_entry>::iterator iter = m_table.begin (); | 
| 242 |            iter != m_table.end (); ++iter) | 
| 243 |         if (!f ((*iter).m_key, &(*iter).m_value, a)) | 
| 244 |           break; | 
| 245 |     } | 
| 246 |  | 
| 247 |   size_t elements () const { return m_table.elements (); } | 
| 248 |  | 
| 249 |   void empty () { m_table.empty(); } | 
| 250 |  | 
| 251 |   /* Return true when there are no elements in this hash map.  */ | 
| 252 |   bool is_empty () const { return m_table.is_empty (); } | 
| 253 |  | 
| 254 |   class iterator | 
| 255 |   { | 
| 256 |   public: | 
| 257 |     explicit iterator (const typename hash_table<hash_entry>::iterator &iter) : | 
| 258 |       m_iter (iter) {} | 
| 259 |  | 
| 260 |     iterator &operator++ () | 
| 261 |     { | 
| 262 |       ++m_iter; | 
| 263 |       return *this; | 
| 264 |     } | 
| 265 |  | 
| 266 |     /* Can't use std::pair here, because GCC before 4.3 don't handle | 
| 267 |        std::pair where template parameters are references well. | 
| 268 |        See PR86739.  */ | 
| 269 |     class reference_pair { | 
| 270 |     public: | 
| 271 |       const Key &first; | 
| 272 |       Value &second; | 
| 273 |  | 
| 274 |       reference_pair (const Key &key, Value &value) : first (key), second (value) {} | 
| 275 |  | 
| 276 |       template <typename K, typename V> | 
| 277 |       operator std::pair<K, V> () const { return std::pair<K, V> (first, second); } | 
| 278 |     }; | 
| 279 |  | 
| 280 |     reference_pair operator* () | 
| 281 |     { | 
| 282 |       hash_entry &e = *m_iter; | 
| 283 |       return reference_pair (e.m_key, e.m_value); | 
| 284 |     } | 
| 285 |  | 
| 286 |     bool operator== (const iterator &other) const | 
| 287 |     { | 
| 288 |       return m_iter == other.m_iter; | 
| 289 |     } | 
| 290 |  | 
| 291 |     bool operator != (const iterator &other) const | 
| 292 |     { | 
| 293 |       return m_iter != other.m_iter; | 
| 294 |     } | 
| 295 |  | 
| 296 |   private: | 
| 297 |     typename hash_table<hash_entry>::iterator m_iter; | 
| 298 |   }; | 
| 299 |  | 
| 300 |   /* Standard iterator retrieval methods.  */ | 
| 301 |  | 
| 302 |   iterator  begin () const { return iterator (m_table.begin ()); } | 
| 303 |   iterator end () const { return iterator (m_table.end ()); } | 
| 304 |  | 
| 305 | private: | 
| 306 |  | 
| 307 |   template<typename T, typename U, typename V> friend void gt_ggc_mx (hash_map<T, U, V> *); | 
| 308 |   template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *); | 
| 309 |   template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *); | 
| 310 |   template<typename T, typename U, typename V> friend void gt_cleare_cache (hash_map<T, U, V> *); | 
| 311 |  | 
| 312 |   hash_table<hash_entry> m_table; | 
| 313 | }; | 
| 314 |  | 
| 315 | /* ggc marking routines.  */ | 
| 316 |  | 
| 317 | template<typename K, typename V, typename H> | 
| 318 | inline void | 
| 319 | gt_ggc_mx (hash_map<K, V, H> *h) | 
| 320 | { | 
| 321 |   gt_ggc_mx (&h->m_table); | 
| 322 | } | 
| 323 |  | 
| 324 | template<typename K, typename V, typename H> | 
| 325 | inline void | 
| 326 | gt_pch_nx (hash_map<K, V, H> *h) | 
| 327 | { | 
| 328 |   gt_pch_nx (&h->m_table); | 
| 329 | } | 
| 330 |  | 
| 331 | template<typename K, typename V, typename H> | 
| 332 | inline void | 
| 333 | gt_cleare_cache (hash_map<K, V, H> *h) | 
| 334 | { | 
| 335 |   if (h) | 
| 336 |     gt_cleare_cache (&h->m_table); | 
| 337 | } | 
| 338 |  | 
| 339 | template<typename K, typename V, typename H> | 
| 340 | inline void | 
| 341 | gt_pch_nx (hash_map<K, V, H> *h, gt_pointer_operator op, void *cookie) | 
| 342 | { | 
| 343 |   op (&h->m_table.m_entries, NULL, cookie); | 
| 344 | } | 
| 345 |  | 
| 346 | enum hm_alloc { hm_heap = false, hm_ggc = true }; | 
| 347 | template<bool ggc, typename K, typename V, typename H> | 
| 348 | inline hash_map<K,V,H> * | 
| 349 | hash_map_maybe_create (hash_map<K,V,H> *&h, | 
| 350 |                        size_t size = default_hash_map_size) | 
| 351 | { | 
| 352 |   if (!h) | 
| 353 |     { | 
| 354 |       if (ggc) | 
| 355 |         h = hash_map<K,V,H>::create_ggc (size); | 
| 356 |       else | 
| 357 |         h = new hash_map<K,V,H> (size); | 
| 358 |     } | 
| 359 |   return h; | 
| 360 | } | 
| 361 |  | 
| 362 | /* Like h->get, but handles null h.  */ | 
| 363 | template<typename K, typename V, typename H> | 
| 364 | inline V* | 
| 365 | hash_map_safe_get (hash_map<K,V,H> *h, const K& k) | 
| 366 | { | 
| 367 |   return h ? h->get (k) : NULL; | 
| 368 | } | 
| 369 |  | 
| 370 | /* Like h->get, but handles null h.  */ | 
| 371 | template<bool ggc, typename K, typename V, typename H> | 
| 372 | inline V& | 
| 373 | hash_map_safe_get_or_insert (hash_map<K,V,H> *&h, const K& k, bool *e = NULL, | 
| 374 |                              size_t size = default_hash_map_size) | 
| 375 | { | 
| 376 |   return hash_map_maybe_create<ggc> (h, size)->get_or_insert (k, e); | 
| 377 | } | 
| 378 |  | 
| 379 | /* Like h->put, but handles null h.  */ | 
| 380 | template<bool ggc, typename K, typename V, typename H> | 
| 381 | inline bool | 
| 382 | hash_map_safe_put (hash_map<K,V,H> *&h, const K& k, const V& v, | 
| 383 |                    size_t size = default_hash_map_size) | 
| 384 | { | 
| 385 |   return hash_map_maybe_create<ggc> (h, size)->put (k, v); | 
| 386 | } | 
| 387 |  | 
| 388 | #endif | 
| 389 |  |