| /* A type-safe hash map that retains the insertion order of keys. |
| Copyright (C) 2019-2022 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC 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. |
| |
| GCC 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 GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| #ifndef GCC_ORDERED_HASH_MAP_H |
| #define GCC_ORDERED_HASH_MAP_H |
| |
| /* Notes: |
| - The keys must be PODs, since vec<> uses assignment to populate slots |
| without properly initializing them. |
| - doesn't have GTY support. |
| - supports removal, but retains order of original insertion. |
| (Removal might be better handled by using a doubly-linked list |
| of nodes, holding the values). */ |
| |
| template<typename KeyId, typename Value, |
| typename Traits> |
| class ordered_hash_map |
| { |
| typedef typename Traits::key_type Key; |
| |
| public: |
| ordered_hash_map () {} |
| |
| ordered_hash_map (const ordered_hash_map &other) |
| : m_map (other.m_map), |
| m_keys (other.m_keys.length ()), |
| m_key_index (other.m_key_index) |
| { |
| unsigned i; |
| Key key; |
| FOR_EACH_VEC_ELT (other.m_keys, i, key) |
| m_keys.quick_push (key); |
| } |
| |
| /* If key K isn't already in the map add key K with value V to the map, and |
| return false. Otherwise set the value of the entry for key K to be V and |
| return true. */ |
| |
| bool put (const Key &k, const Value &v) |
| { |
| bool existed = m_map.put (k, v); |
| if (!existed) |
| { |
| bool key_present; |
| int &slot = m_key_index.get_or_insert (k, &key_present); |
| if (!key_present) |
| { |
| slot = m_keys.length (); |
| m_keys.safe_push (k); |
| } |
| } |
| return existed; |
| } |
| |
| /* If the passed in key is in the map return its value otherwise NULL. */ |
| |
| Value *get (const Key &k) |
| { |
| return m_map.get (k); |
| } |
| |
| /* Removing a key removes it from the map, but retains the insertion |
| order. */ |
| |
| void remove (const Key &k) |
| { |
| m_map.remove (k); |
| } |
| |
| size_t elements () const { return m_map.elements (); } |
| |
| class iterator |
| { |
| public: |
| explicit iterator (const ordered_hash_map &map, unsigned idx) : |
| m_ordered_hash_map (map), m_idx (idx) {} |
| |
| iterator &operator++ () |
| { |
| /* Increment m_idx until we find a non-deleted element, or go beyond |
| the end. */ |
| while (1) |
| { |
| ++m_idx; |
| if (valid_index_p ()) |
| break; |
| } |
| return *this; |
| } |
| |
| /* Can't use std::pair here, because GCC before 4.3 don't handle |
| std::pair where template parameters are references well. |
| See PR86739. */ |
| struct reference_pair { |
| const Key &first; |
| Value &second; |
| |
| reference_pair (const Key &key, Value &value) |
| : first (key), second (value) {} |
| |
| template <typename K, typename V> |
| operator std::pair<K, V> () const { return std::pair<K, V> (first, second); } |
| }; |
| |
| reference_pair operator* () |
| { |
| const Key &k = m_ordered_hash_map.m_keys[m_idx]; |
| Value *slot |
| = const_cast<ordered_hash_map &> (m_ordered_hash_map).get (k); |
| gcc_assert (slot); |
| return reference_pair (k, *slot); |
| } |
| |
| bool |
| operator != (const iterator &other) const |
| { |
| return m_idx != other.m_idx; |
| } |
| |
| /* Treat one-beyond-the-end as valid, for handling the "end" case. */ |
| |
| bool valid_index_p () const |
| { |
| if (m_idx > m_ordered_hash_map.m_keys.length ()) |
| return false; |
| if (m_idx == m_ordered_hash_map.m_keys.length ()) |
| return true; |
| const Key &k = m_ordered_hash_map.m_keys[m_idx]; |
| Value *slot |
| = const_cast<ordered_hash_map &> (m_ordered_hash_map).get (k); |
| return slot != NULL; |
| } |
| |
| const ordered_hash_map &m_ordered_hash_map; |
| unsigned m_idx; |
| }; |
| |
| /* Standard iterator retrieval methods. */ |
| |
| iterator begin () const |
| { |
| iterator i = iterator (*this, 0); |
| while (!i.valid_index_p () && i != end ()) |
| ++i; |
| return i; |
| } |
| iterator end () const { return iterator (*this, m_keys.length ()); } |
| |
| private: |
| /* The assignment operator is not yet implemented; prevent erroneous |
| usage of unsafe compiler-generated one. */ |
| void operator= (const ordered_hash_map &); |
| |
| /* The underlying map. */ |
| hash_map<KeyId, Value, Traits> m_map; |
| |
| /* The ordering of the keys. */ |
| auto_vec<Key> m_keys; |
| |
| /* For each key that's ever been in the map, its index within m_keys. */ |
| hash_map<KeyId, int> m_key_index; |
| }; |
| |
| /* Two-argument form. */ |
| |
| template<typename Key, typename Value, |
| typename Traits = simple_hashmap_traits<default_hash_traits<Key>, |
| Value> > |
| class ordered_hash_map; |
| |
| #endif /* GCC_ORDERED_HASH_MAP_H */ |