Home | History | Annotate | Line # | Download | only in gcc
      1 /* A type-safe hash map.
      2    Copyright (C) 2014-2022 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 = hash_entry::is_empty (*e);
    173       if (ins)
    174 	{
    175 	  e->m_key = k;
    176 	  new ((void *) &e->m_value) Value (v);
    177 	}
    178       else
    179 	e->m_value = v;
    180 
    181       return !ins;
    182     }
    183 
    184   /* If the passed in key is in the map return pointer to its value
    185      otherwise NULL.  */
    186 
    187   Value *get (const Key &k)
    188     {
    189       hash_entry &e = m_table.find_with_hash (k, Traits::hash (k));
    190       return Traits::is_empty (e) ? NULL : &e.m_value;
    191     }
    192 
    193   /* Return a reference to the value for the passed in key, creating the entry
    194      if it doesn't already exist.  If existed is not NULL then it is set to
    195      false if the key was not previously in the map, and true otherwise.  */
    196 
    197   Value &get_or_insert (const Key &k, bool *existed = NULL)
    198     {
    199       hash_entry *e = m_table.find_slot_with_hash (k, Traits::hash (k),
    200 						   INSERT);
    201       bool ins = Traits::is_empty (*e);
    202       if (ins)
    203 	{
    204 	  e->m_key = k;
    205 	  new ((void *)&e->m_value) Value ();
    206 	}
    207 
    208       if (existed != NULL)
    209 	*existed = !ins;
    210 
    211       return e->m_value;
    212     }
    213 
    214   void remove (const Key &k)
    215     {
    216       m_table.remove_elt_with_hash (k, Traits::hash (k));
    217     }
    218 
    219   /* Call the call back on each pair of key and value with the passed in
    220      arg until either the call back returns false or all pairs have been seen.
    221      The traversal is unordered.  */
    222 
    223   template<typename Arg, bool (*f)(const typename Traits::key_type &,
    224 				   const Value &, Arg)>
    225   void traverse (Arg a) const
    226     {
    227       for (typename hash_table<hash_entry>::iterator iter = m_table.begin ();
    228 	   iter != m_table.end (); ++iter)
    229 	if (!f ((*iter).m_key, (*iter).m_value, a))
    230 	  break;
    231     }
    232 
    233   template<typename Arg, bool (*f)(const typename Traits::key_type &,
    234 				   Value *, Arg)>
    235   void traverse (Arg a) const
    236     {
    237       for (typename hash_table<hash_entry>::iterator iter = m_table.begin ();
    238 	   iter != m_table.end (); ++iter)
    239 	if (!f ((*iter).m_key, &(*iter).m_value, a))
    240 	  break;
    241     }
    242 
    243   size_t elements () const { return m_table.elements (); }
    244 
    245   void empty () { m_table.empty(); }
    246 
    247   /* Return true when there are no elements in this hash map.  */
    248   bool is_empty () const { return m_table.is_empty (); }
    249 
    250   class iterator
    251   {
    252   public:
    253     explicit iterator (const typename hash_table<hash_entry>::iterator &iter) :
    254       m_iter (iter) {}
    255 
    256     iterator &operator++ ()
    257     {
    258       ++m_iter;
    259       return *this;
    260     }
    261 
    262     /* Can't use std::pair here, because GCC before 4.3 don't handle
    263        std::pair where template parameters are references well.
    264        See PR86739.  */
    265     class reference_pair {
    266     public:
    267       const Key &first;
    268       Value &second;
    269 
    270       reference_pair (const Key &key, Value &value) : first (key), second (value) {}
    271 
    272       template <typename K, typename V>
    273       operator std::pair<K, V> () const { return std::pair<K, V> (first, second); }
    274     };
    275 
    276     reference_pair operator* ()
    277     {
    278       hash_entry &e = *m_iter;
    279       return reference_pair (e.m_key, e.m_value);
    280     }
    281 
    282     bool operator== (const iterator &other) const
    283     {
    284       return m_iter == other.m_iter;
    285     }
    286 
    287     bool operator != (const iterator &other) const
    288     {
    289       return m_iter != other.m_iter;
    290     }
    291 
    292   private:
    293     typename hash_table<hash_entry>::iterator m_iter;
    294   };
    295 
    296   /* Standard iterator retrieval methods.  */
    297 
    298   iterator  begin () const { return iterator (m_table.begin ()); }
    299   iterator end () const { return iterator (m_table.end ()); }
    300 
    301 private:
    302 
    303   template<typename T, typename U, typename V> friend void gt_ggc_mx (hash_map<T, U, V> *);
    304   template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *);
    305   template<typename T, typename U, typename V> friend void gt_pch_nx (hash_map<T, U, V> *, gt_pointer_operator, void *);
    306   template<typename T, typename U, typename V> friend void gt_cleare_cache (hash_map<T, U, V> *);
    307 
    308   hash_table<hash_entry> m_table;
    309 };
    310 
    311 /* ggc marking routines.  */
    312 
    313 template<typename K, typename V, typename H>
    314 static inline void
    315 gt_ggc_mx (hash_map<K, V, H> *h)
    316 {
    317   gt_ggc_mx (&h->m_table);
    318 }
    319 
    320 template<typename K, typename V, typename H>
    321 static inline void
    322 gt_pch_nx (hash_map<K, V, H> *h)
    323 {
    324   gt_pch_nx (&h->m_table);
    325 }
    326 
    327 template<typename K, typename V, typename H>
    328 static inline void
    329 gt_cleare_cache (hash_map<K, V, H> *h)
    330 {
    331   if (h)
    332     gt_cleare_cache (&h->m_table);
    333 }
    334 
    335 template<typename K, typename V, typename H>
    336 static inline void
    337 gt_pch_nx (hash_map<K, V, H> *h, gt_pointer_operator op, void *cookie)
    338 {
    339   op (&h->m_table.m_entries, NULL, cookie);
    340 }
    341 
    342 enum hm_alloc { hm_heap = false, hm_ggc = true };
    343 template<bool ggc, typename K, typename V, typename H>
    344 inline hash_map<K,V,H> *
    345 hash_map_maybe_create (hash_map<K,V,H> *&h,
    346 		       size_t size = default_hash_map_size)
    347 {
    348   if (!h)
    349     {
    350       if (ggc)
    351 	h = hash_map<K,V,H>::create_ggc (size);
    352       else
    353 	h = new hash_map<K,V,H> (size);
    354     }
    355   return h;
    356 }
    357 
    358 /* Like h->get, but handles null h.  */
    359 template<typename K, typename V, typename H>
    360 inline V*
    361 hash_map_safe_get (hash_map<K,V,H> *h, const K& k)
    362 {
    363   return h ? h->get (k) : NULL;
    364 }
    365 
    366 /* Like h->get, but handles null h.  */
    367 template<bool ggc, typename K, typename V, typename H>
    368 inline V&
    369 hash_map_safe_get_or_insert (hash_map<K,V,H> *&h, const K& k, bool *e = NULL,
    370 			     size_t size = default_hash_map_size)
    371 {
    372   return hash_map_maybe_create<ggc> (h, size)->get_or_insert (k, e);
    373 }
    374 
    375 /* Like h->put, but handles null h.  */
    376 template<bool ggc, typename K, typename V, typename H>
    377 inline bool
    378 hash_map_safe_put (hash_map<K,V,H> *&h, const K& k, const V& v,
    379 		   size_t size = default_hash_map_size)
    380 {
    381   return hash_map_maybe_create<ggc> (h, size)->put (k, v);
    382 }
    383 
    384 #endif
    385