From d06af193b769b538181f8922fcb118ea673f2f2c Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Fri, 12 Jul 2019 14:44:37 -0400
Subject: [PATCH 27/96] FIXME: implement ordered_hash_map::remove

FIXME: fixups for ordered-hash-map.h

FIXME: fixup to ordered-hash-map.h

FIXME: test coverage for ordered_hash_maps
---
 gcc/ordered-hash-map-tests.cc | 122 ++++++++++++++++++++++++++++++++++--------
 gcc/ordered-hash-map.h        |  75 +++++++++++++++++++++++---
 2 files changed, 166 insertions(+), 31 deletions(-)

diff --git a/gcc/ordered-hash-map-tests.cc b/gcc/ordered-hash-map-tests.cc
index e324b17..f7cf359 100644
--- a/gcc/ordered-hash-map-tests.cc
+++ b/gcc/ordered-hash-map-tests.cc
@@ -38,6 +38,19 @@ along with GCC; see the file COPYING3.  If not see
 
 namespace selftest {
 
+/* FIXME.  */
+
+template <typename Key, typename Value>
+static void
+get_kv_pairs (const ordered_hash_map <Key, Value> &m,
+	      auto_vec<std::pair<Key, Value> > *out_kvs)
+{
+  for (ordered_hash_map <const char *, int>::iterator iter = m.begin ();
+       iter != m.end ();
+       ++iter)
+    out_kvs->safe_push (std::make_pair ((*iter).first, (*iter).second));
+}
+
 /* Construct an ordered_hash_map <const char *, int> and verify that
    various operations work correctly.  */
 
@@ -77,29 +90,90 @@ test_map_of_strings_to_int ()
   /* FIXME: maybe combine the above with hash-map-tests.c.  */
 
   /* Verify that the order of insertion is preserved.  */
-  auto_vec<const char *> keys;
-  auto_vec<int> values;
-  for (ordered_hash_map <const char *, int>::iterator iter = m.begin ();
-       iter != m.end ();
-       ++iter)
-    {
-      keys.safe_push ((*iter).first);
-      values.safe_push ((*iter).second);
-    }
-  ASSERT_EQ (keys.length (), 6);
-  ASSERT_EQ (values.length (), 6);
-  ASSERT_EQ (keys[0], ostrich);
-  ASSERT_EQ (values[0], 2);
-  ASSERT_EQ (keys[1], elephant);
-  ASSERT_EQ (values[1], 4);
-  ASSERT_EQ (keys[2], ant);
-  ASSERT_EQ (values[2], 6);
-  ASSERT_EQ (keys[3], spider);
-  ASSERT_EQ (values[3], 8);
-  ASSERT_EQ (keys[4], millipede);
-  ASSERT_EQ (values[4], 750);
-  ASSERT_EQ (keys[5], eric);
-  ASSERT_EQ (values[5], 3);
+  auto_vec<std::pair<const char *, int> > kvs;
+  get_kv_pairs (m, &kvs);
+  ASSERT_EQ (kvs.length (), 6);
+  ASSERT_EQ (kvs[0].first, ostrich);
+  ASSERT_EQ (kvs[0].second, 2);
+  ASSERT_EQ (kvs[1].first, elephant);
+  ASSERT_EQ (kvs[1].second, 4);
+  ASSERT_EQ (kvs[2].first, ant);
+  ASSERT_EQ (kvs[2].second, 6);
+  ASSERT_EQ (kvs[3].first, spider);
+  ASSERT_EQ (kvs[3].second, 8);
+  ASSERT_EQ (kvs[4].first, millipede);
+  ASSERT_EQ (kvs[4].second, 750);
+  ASSERT_EQ (kvs[5].first, eric);
+  ASSERT_EQ (kvs[5].second, 3);
+}
+
+/* Verify that we can remove items from an ordered_hash_map.  */
+
+static void
+test_removal ()
+{
+  ordered_hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  ASSERT_EQ (false, m.put (ostrich, 2));
+
+  ASSERT_EQ (1, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+
+  {
+    auto_vec<std::pair<const char *, int> > kvs;
+    get_kv_pairs (m, &kvs);
+    ASSERT_EQ (kvs.length (), 1);
+    ASSERT_EQ (kvs[0].first, ostrich);
+    ASSERT_EQ (kvs[0].second, 2);
+  }
+
+  m.remove (ostrich);
+
+  ASSERT_EQ (0, m.elements ());
+  {
+    auto_vec<std::pair<const char *, int> > kvs;
+    get_kv_pairs (m, &kvs);
+    ASSERT_EQ (kvs.length (), 0);
+  }
+
+  /* Reinsertion (with a different value).  */
+  ASSERT_EQ (false, m.put (ostrich, 42));
+  ASSERT_EQ (1, m.elements ());
+  ASSERT_EQ (42, *m.get (ostrich));
+  {
+    auto_vec<std::pair<const char *, int> > kvs;
+    get_kv_pairs (m, &kvs);
+    ASSERT_EQ (kvs.length (), 1);
+    ASSERT_EQ (kvs[0].first, ostrich);
+    ASSERT_EQ (kvs[0].second, 42);
+  }
+}
+
+/* Verify that ordered_hash_map's copy-ctor works.  */
+
+static void
+test_copy_ctor ()
+{
+  ordered_hash_map <const char *, int> m;
+
+  const char *ostrich = "ostrich";
+  ASSERT_EQ (false, m.put (ostrich, 2));
+
+  ASSERT_EQ (1, m.elements ());
+  ASSERT_EQ (2, *m.get (ostrich));
+
+  ordered_hash_map <const char *, int> copy (m);
+  ASSERT_EQ (1, copy.elements ());
+  ASSERT_EQ (2, *copy.get (ostrich));
+
+  /* Remove from source.  */
+  m.remove (ostrich);
+  ASSERT_EQ (0, m.elements ());
+
+  /* Copy should be unaffected.  */
+  ASSERT_EQ (1, copy.elements ());
+  ASSERT_EQ (2, *copy.get (ostrich));
 }
 
 /* Run all of the selftests within this file.  */
@@ -108,6 +182,8 @@ void
 ordered_hash_map_tests_cc_tests ()
 {
   test_map_of_strings_to_int ();
+  test_removal ();
+  test_copy_ctor ();
 }
 
 } // namespace selftest
diff --git a/gcc/ordered-hash-map.h b/gcc/ordered-hash-map.h
index 8ce58e3..59ec11c 100644
--- a/gcc/ordered-hash-map.h
+++ b/gcc/ordered-hash-map.h
@@ -22,8 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #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.
-   - doesn't support removal.  */
+   - 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>
@@ -32,6 +36,18 @@ 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
@@ -41,7 +57,15 @@ public:
   {
     bool existed = m_map.put (k, v);
     if (!existed)
-      m_keys.safe_push (k);
+      {
+        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;
   }
 
@@ -52,6 +76,14 @@ public:
     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
@@ -62,7 +94,14 @@ public:
 
     iterator &operator++ ()
     {
-      ++m_idx;
+       /* 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;
     }
 
@@ -71,9 +110,9 @@ public:
        See PR86739.  */
     struct reference_pair {
       const Key &first;
-      const Value &second;
+      Value &second;
 
-      reference_pair (const Key &key, const Value &value)
+      reference_pair (const Key &key, Value &value)
       : first (key), second (value) {}
 
       template <typename K, typename V>
@@ -83,7 +122,7 @@ public:
     reference_pair operator* ()
     {
       const Key &k = m_ordered_hash_map.m_keys[m_idx];
-      const Value *slot
+      Value *slot
         = const_cast<ordered_hash_map &> (m_ordered_hash_map).get (k);
       gcc_assert (slot);
       return reference_pair (k, *slot);
@@ -95,19 +134,39 @@ public:
       return m_idx != other.m_idx;
     }
 
-  private:
+    /* 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 { return iterator (*this, 0); }
+  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:
   hash_map<KeyId, Value, Traits> m_map;
   auto_vec<KeyId> m_keys;
+  hash_map<KeyId, int> m_key_index;
 };
 
 /* Two-argument form.  */
-- 
1.8.5.3

