You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
4.9KB

  1. /* A type-safe hash map that retains the insertion order of keys.
  2. Copyright (C) 2019-2020 Free Software Foundation, Inc.
  3. This file is part of GCC.
  4. GCC is free software; you can redistribute it and/or modify it under
  5. the terms of the GNU General Public License as published by the Free
  6. Software Foundation; either version 3, or (at your option) any later
  7. version.
  8. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  9. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  10. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  11. for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GCC; see the file COPYING3. If not see
  14. <http://www.gnu.org/licenses/>. */
  15. #ifndef GCC_ORDERED_HASH_MAP_H
  16. #define GCC_ORDERED_HASH_MAP_H
  17. /* Notes:
  18. - The keys must be PODs, since vec<> uses assignment to populate slots
  19. without properly initializing them.
  20. - doesn't have GTY support.
  21. - supports removal, but retains order of original insertion.
  22. (Removal might be better handled by using a doubly-linked list
  23. of nodes, holding the values). */
  24. template<typename KeyId, typename Value,
  25. typename Traits>
  26. class ordered_hash_map
  27. {
  28. typedef typename Traits::key_type Key;
  29. public:
  30. ordered_hash_map () {}
  31. ordered_hash_map (const ordered_hash_map &other)
  32. : m_map (other.m_map),
  33. m_keys (other.m_keys.length ()),
  34. m_key_index (other.m_key_index)
  35. {
  36. unsigned i;
  37. Key key;
  38. FOR_EACH_VEC_ELT (other.m_keys, i, key)
  39. m_keys.quick_push (key);
  40. }
  41. /* If key K isn't already in the map add key K with value V to the map, and
  42. return false. Otherwise set the value of the entry for key K to be V and
  43. return true. */
  44. bool put (const Key &k, const Value &v)
  45. {
  46. bool existed = m_map.put (k, v);
  47. if (!existed)
  48. {
  49. bool key_present;
  50. int &slot = m_key_index.get_or_insert (k, &key_present);
  51. if (!key_present)
  52. {
  53. slot = m_keys.length ();
  54. m_keys.safe_push (k);
  55. }
  56. }
  57. return existed;
  58. }
  59. /* If the passed in key is in the map return its value otherwise NULL. */
  60. Value *get (const Key &k)
  61. {
  62. return m_map.get (k);
  63. }
  64. /* Removing a key removes it from the map, but retains the insertion
  65. order. */
  66. void remove (const Key &k)
  67. {
  68. m_map.remove (k);
  69. }
  70. size_t elements () const { return m_map.elements (); }
  71. class iterator
  72. {
  73. public:
  74. explicit iterator (const ordered_hash_map &map, unsigned idx) :
  75. m_ordered_hash_map (map), m_idx (idx) {}
  76. iterator &operator++ ()
  77. {
  78. /* Increment m_idx until we find a non-deleted element, or go beyond
  79. the end. */
  80. while (1)
  81. {
  82. ++m_idx;
  83. if (valid_index_p ())
  84. break;
  85. }
  86. return *this;
  87. }
  88. /* Can't use std::pair here, because GCC before 4.3 don't handle
  89. std::pair where template parameters are references well.
  90. See PR86739. */
  91. struct reference_pair {
  92. const Key &first;
  93. Value &second;
  94. reference_pair (const Key &key, Value &value)
  95. : first (key), second (value) {}
  96. template <typename K, typename V>
  97. operator std::pair<K, V> () const { return std::pair<K, V> (first, second); }
  98. };
  99. reference_pair operator* ()
  100. {
  101. const Key &k = m_ordered_hash_map.m_keys[m_idx];
  102. Value *slot
  103. = const_cast<ordered_hash_map &> (m_ordered_hash_map).get (k);
  104. gcc_assert (slot);
  105. return reference_pair (k, *slot);
  106. }
  107. bool
  108. operator != (const iterator &other) const
  109. {
  110. return m_idx != other.m_idx;
  111. }
  112. /* Treat one-beyond-the-end as valid, for handling the "end" case. */
  113. bool valid_index_p () const
  114. {
  115. if (m_idx > m_ordered_hash_map.m_keys.length ())
  116. return false;
  117. if (m_idx == m_ordered_hash_map.m_keys.length ())
  118. return true;
  119. const Key &k = m_ordered_hash_map.m_keys[m_idx];
  120. Value *slot
  121. = const_cast<ordered_hash_map &> (m_ordered_hash_map).get (k);
  122. return slot != NULL;
  123. }
  124. const ordered_hash_map &m_ordered_hash_map;
  125. unsigned m_idx;
  126. };
  127. /* Standard iterator retrieval methods. */
  128. iterator begin () const
  129. {
  130. iterator i = iterator (*this, 0);
  131. while (!i.valid_index_p () && i != end ())
  132. ++i;
  133. return i;
  134. }
  135. iterator end () const { return iterator (*this, m_keys.length ()); }
  136. private:
  137. /* The assignment operator is not yet implemented; prevent erroneous
  138. usage of unsafe compiler-generated one. */
  139. void operator= (const ordered_hash_map &);
  140. /* The underlying map. */
  141. hash_map<KeyId, Value, Traits> m_map;
  142. /* The ordering of the keys. */
  143. auto_vec<Key> m_keys;
  144. /* For each key that's ever been in the map, its index within m_keys. */
  145. hash_map<KeyId, int> m_key_index;
  146. };
  147. /* Two-argument form. */
  148. template<typename Key, typename Value,
  149. typename Traits = simple_hashmap_traits<default_hash_traits<Key>,
  150. Value> >
  151. class ordered_hash_map;
  152. #endif /* GCC_ORDERED_HASH_MAP_H */