/* A type-safe hash map that retains the insertion order of keys. Copyright (C) 2019-2020 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 . */ #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 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 operator std::pair () const { return std::pair (first, second); } }; reference_pair operator* () { const Key &k = m_ordered_hash_map.m_keys[m_idx]; Value *slot = const_cast (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 (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 m_map; /* The ordering of the keys. */ auto_vec m_keys; /* For each key that's ever been in the map, its index within m_keys. */ hash_map m_key_index; }; /* Two-argument form. */ template, Value> > class ordered_hash_map; #endif /* GCC_ORDERED_HASH_MAP_H */