[Aptitude-svn-commit] r3970 - in branches/aptitude-0.3/aptitude: . src/generic tests

Daniel Burrows dburrows at costa.debian.org
Sat Aug 27 19:22:48 UTC 2005


Author: dburrows
Date: Sat Aug 27 19:22:37 2005
New Revision: 3970

Modified:
   branches/aptitude-0.3/aptitude/ChangeLog
   branches/aptitude-0.3/aptitude/src/generic/immset.h
   branches/aptitude-0.3/aptitude/tests/test_wtree.cc
Log:
Add support for removing and finding elements to the wtree class.

Modified: branches/aptitude-0.3/aptitude/ChangeLog
==============================================================================
--- branches/aptitude-0.3/aptitude/ChangeLog	(original)
+++ branches/aptitude-0.3/aptitude/ChangeLog	Sat Aug 27 19:22:37 2005
@@ -1,6 +1,13 @@
+2005-08-27  Daniel Burrows  <dburrows at debian.org>
+
+	* src/generic/immset.h, tests/test_wtree.cc:
+
+	  Add support for removing elements from a wtree and for finding a
+	  particular element in the tree.
+
 2005-08-26  Daniel Burrows  <dburrows at debian.org>
 
-	* src/generic/wtree.h, tests/Makefile.am, tests/test_wtree.h:
+	* src/generic/immset.h, tests/Makefile.am, tests/test_wtree.h:
 
 	  Write a basic framework for weight-based immutable trees.  These
 	  trees explicitly share memory between different versions of a

Modified: branches/aptitude-0.3/aptitude/src/generic/immset.h
==============================================================================
--- branches/aptitude-0.3/aptitude/src/generic/immset.h	(original)
+++ branches/aptitude-0.3/aptitude/src/generic/immset.h	Sat Aug 27 19:22:37 2005
@@ -336,6 +336,13 @@
      */
     class const_iterator
     {
+      /** If the first entry of the pair is \b true, then we have not
+       *  yet descended into the right subtree of this entry.  For
+       *  nodes other than the las tone, if the first entry is \b
+       *  false, then when the node becomes the last node again its
+       *  right child will be entered; otherwise the node itself will
+       *  be visited.
+       */
       typedef std::pair<bool, node > path_entry;
 
       std::vector<path_entry> path;
@@ -409,44 +416,93 @@
     /** Root of the tree. */
     node root;
 
-    /** An 'insert' based on tree nodes.  Returns a rebalanced tree
-     *  containing the given information; doesn't update existing
-     *  nodes with equivalent keys.
+    /** Returns a balanced tree constructed by adding x to n.
      */
-    node insert(const node &n, const Val &x) const
+    node add(const node &n, const Val &x) const
     {
-      if(n.empty()) return node(x, node(), node());
+      if(n.empty())
+	return node(x, node(), node());
       else if(value_compare(x, n.getVal()))
 	return node(n.getVal(),
-		    insert(n.getLeft(), x),
+		    add(n.getLeft(), x),
 		    n.getRight()).rebalance();
       else if(value_compare(n.getVal(), x))
 	return node(n.getVal(),
 		    n.getLeft(),
-		    insert(n.getRight(), x)).rebalance();
+		    add(n.getRight(), x)).rebalance();
       else
 	return n;
     }
 
-    /** An 'insert' based on tree nodes.  Returns a rebalanced tree
-     *  containing the given information, updating existing nodes with
-     *  equivalent keys.
+    /** Returns a balanced tree constructed by adding x to n.  Will
+     *  replace existing nodes equivalent to x.
      */
-    node insertUpdate(const node &n, const Val &x) const
+    node addUpdate(const node &n, const Val &x) const
     {
-      if(n.empty()) return node(x, node(), node());
+      if(n.empty())
+        return node(x, node(), node());
       else if(value_compare(x, n.getVal()))
 	return node(n.getVal(),
-		    insert(n.getLeft(), x),
+		    addUpdate(n.getLeft(), x),
 		    n.getRight()).rebalance();
       else if(value_compare(n.getVal(), x))
 	return node(n.getVal(),
 		    n.getLeft(),
-		    insert(n.getRight(), x)).rebalance();
+		    addUpdate(n.getRight(), x)).rebalance();
       else
 	return node(x, n.getLeft(), n.getRight());
     }
 
+    /** Given a node, find and return its minimum element while
+     *  simultaneously constructing a new (balanced) node that doesn't
+     *  contain the minimum.
+     */
+    static std::pair<node, Val> find_and_remove_min(const node &n)
+    {
+      if(n.getLeft().isValid())
+      {
+	std::pair<node, Val> tmp = find_and_remove_min(n.getLeft());
+	  return std::pair<node, Val>(node(n.getVal(),
+					   tmp.first, n.getRight()).rebalance(),
+				      tmp.second);
+      }
+      else
+      {
+	return std::pair<node, Val>(node(), n.getVal());
+      }
+    }
+
+    /** Join together two trees; every element of l must be less than
+     *  every element of r.
+     */
+    static node splice_trees(const node &l, const node &r)
+    {
+      if(r.empty())
+        return l;
+      else if(l.empty())
+        return r;
+
+      std::pair<node, Val> tmp = find_and_remove_min(r);
+      return node(tmp.second, l, tmp.first);
+    }
+
+    /** Remove the given value from the given tree. */
+    node remove(const node &n, const Val &x) const
+    {
+      if(n.empty())
+        return n;
+      else if(value_compare(x, n.getVal()))
+        return node(n.getVal(),
+		    remove(n.getLeft(), x),
+		    n.getRight()).rebalance();
+      else if(value_compare(n.getVal(), x))
+        return node(n.getVal(),
+		    n.getLeft(),
+		    remove(n.getRight(), x)).rebalance();
+      else // found an equivalent node:
+        return splice_trees(n.getLeft(), n.getRight());
+    }
+
     wtree(const node &n)
       :root(n)
     {
@@ -462,15 +518,61 @@
      *  old tree; instead, it returns a new tree containing the
      *  element in addition to the elements of the old tree.
      */
-    static wtree insert(const wtree &old, const Val &x)
+    static wtree add(const wtree &old, const Val &x)
     {
       return old.insert(old.root, x);
     }
 
     /** Like insert, but updates existing equivalent elements. */
-    static wtree insertUpdate(const wtree &old, const Val &x)
+    static wtree addUpdate(const wtree &old, const Val &x)
     {
-      return old.insertUpdate(old.root, x);
+      return old.addUpdate(old.root, x);
+    }
+
+    /** Remove x from the tree. */
+    static wtree remove(const wtree &old, const Val &x)
+    {
+      return old.remove(old.root, x);
+    }
+
+    /** Do an "in-place" update of this wtree, by replacing the root
+     *  with a new root.
+     */
+    void insert(const Val &x)
+    {
+      root = add(root, x);
+    }
+
+    /** Similar. */
+    void insertUpdate(const Val &x)
+    {
+      root = addUpdate(root, x);
+    }
+
+    /** Similar. */
+    void erase(const Val &x)
+    {
+      root = remove(root, x);
+    }
+
+    /** Find a tree node by value.  \return the node, or an invalid
+     *	node if none exists.
+     */
+    node find_node(const Val &x)
+    {
+      node rval = root;
+
+      while(rval.isValid())
+      {
+	if(value_compare(x, rval.getVal()))
+	  rval = rval.getLeft();
+	else if(value_compare(rval.getVal(), x))
+	  rval = rval.getRight();
+	else
+	  return rval;
+      }
+
+      return rval;
     }
 
     const_iterator begin() const

Modified: branches/aptitude-0.3/aptitude/tests/test_wtree.cc
==============================================================================
--- branches/aptitude-0.3/aptitude/tests/test_wtree.cc	(original)
+++ branches/aptitude-0.3/aptitude/tests/test_wtree.cc	Sat Aug 27 19:22:37 2005
@@ -29,7 +29,7 @@
   CPPUNIT_TEST_SUITE(WTreeTest);
 
   CPPUNIT_TEST(testNodeRotate);
-  CPPUNIT_TEST(testInsertIterate);
+  CPPUNIT_TEST(generalWTreeTest);
 
   CPPUNIT_TEST_SUITE_END();
 public:
@@ -102,162 +102,210 @@
     CPPUNIT_ASSERT(b_right.getVal() == 8);
   }
 
-  void testInsertIterate()
+  static bool WTreeValuesMatch(const wtree<int> &t,
+			       const int *values, int count)
   {
-    wtree<int> t;
-
-    CPPUNIT_ASSERT(t.begin() == t.end());
-    CPPUNIT_ASSERT(t.empty());
-    CPPUNIT_ASSERT(t.size() == 0);
-
-
-
-    t = wtree<int>::insert(t, 5);
-
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 1);
-
-    wtree<int>::const_iterator i = t.begin();
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
-
-    ++i;
-    CPPUNIT_ASSERT(i == t.end());
-
-
-
-
-    t = wtree<int>::insert(t, 3);
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 2);
-
-    i = t.begin();
-
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 3);
+    if(count == 0)
+      return t.empty();
+    else
+      {
+	wtree<int>::const_iterator i = t.begin();
+
+	while(i != t.end() && count > 0)
+	  {
+	    if(*values != *i)
+	      return false;
+
+	    ++i;
+	    ++values;
+	    --count;
+	  }
 
-    ++i;
-
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
-
-    ++i;
-
-    CPPUNIT_ASSERT(i == t.end());
-
-
-
-    t = wtree<int>::insert(t, 8);
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 3);
-
-    i = t.begin();
-
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 3);
-
-    ++i;
+	return i == t.end() && count == 0;
+      }
+  }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
+  static void dumpMatchFailure(std::ostream &out,
+			       const wtree<int> &t,
+			       const int *values,
+			       int count)
+  {
+    out << "Expected {";
+    while(count > 0)
+      {
+	out << *values;
+	if(count > 1)
+	  out << ", ";
+
+	++values;
+	--count;
+      }
+
+    out << "}; got {";
+
+    for(wtree<int>::const_iterator i = t.begin(); i != t.end(); ++i)
+      {
+	if(i != t.begin())
+	  out << ", ";
 
-    ++i;
+	out << *i;
+      }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 8);
+    out << "}";
+  }
 
-    ++i;
+  /** A macro to assert that a given wtree has exactly the listed
+   *  contents.  A macro is used instead of a procedure so that line
+   *  numbers in test failures are useful.
+   */
+#define assertWTreeValues(t, values, count) \
+do  { \
+  if(!WTreeValuesMatch(t, values, count)) \
+    { \
+      std::ostringstream out; \
+      dumpMatchFailure(out, t, values, count); \
+      CPPUNIT_FAIL(out.str()); \
+    } } while(0)
 
-    CPPUNIT_ASSERT(i == t.end());
+  void generalWTreeTest()
+  {
+    wtree<int> t;
 
+    assertWTreeValues(t, NULL, 0);
 
+    {
+      t.insert(5);
+      int vals[] = {5};
+      assertWTreeValues(t, vals, 1);
+    }
 
-    t = wtree<int>::insert(t, 7);
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 4);
+    CPPUNIT_ASSERT(!t.find_node(3).isValid());
 
-    i = t.begin();
+    {
+      wtree_node<int> found = t.find_node(5);
+      CPPUNIT_ASSERT(found.isValid());
+      CPPUNIT_ASSERT_EQUAL(found.getVal(), 5);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 3);
 
-    ++i;
+    {
+      t.insert(3);
+      int vals[] = {3, 5};
+      assertWTreeValues(t, vals, 2);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
+    {
+      t.insert(8);
+      int vals[] = {3, 5, 8};
+      assertWTreeValues(t, vals, 3);
+    }
 
-    ++i;
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 7);
+    {
+      t.insert(7);
+      int vals[] = {3, 5, 7, 8};
+      assertWTreeValues(t, vals, 4);
+    }
 
-    ++i;
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 8);
+    CPPUNIT_ASSERT(!t.find_node(9).isValid());
 
-    ++i;
+    {
+      wtree_node<int> found = t.find_node(5);
 
-    CPPUNIT_ASSERT(i == t.end());
+      CPPUNIT_ASSERT(found.isValid());
+      CPPUNIT_ASSERT_EQUAL(found.getVal(), 5);
+    }
 
+    {
+      t.insert(4);
+      int vals[] = {3, 4, 5, 7, 8};
+      assertWTreeValues(t, vals, 5);
+    }
 
-    t = wtree<int>::insert(t, 3);
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 4);
 
-    i = t.begin();
+    {
+      t.insert(3);
+      int vals[] = {3, 4, 5, 7, 8};
+      assertWTreeValues(t, vals, 5);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 3);
 
-    ++i;
+    {
+      t.insertUpdate(3);
+      int vals[] = {3, 4, 5, 7, 8};
+      assertWTreeValues(t, vals, 5);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
 
-    ++i;
+    {
+      t.insertUpdate(6);
+      int vals[] = {3, 4, 5, 6, 7, 8};
+      assertWTreeValues(t, vals, 6);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 7);
 
-    ++i;
+    {
+      t.erase(5);
+      int vals[] = {3, 4, 6, 7, 8};
+      assertWTreeValues(t, vals, 5);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 8);
 
-    ++i;
+    {
+      t.erase(7);
+      int vals[] = {3, 4, 6, 8};
+      assertWTreeValues(t, vals, 4);
+    }
 
-    CPPUNIT_ASSERT(i == t.end());
+    {
+      t.erase(7);
+      int vals[] = {3, 4, 6, 8};
+      assertWTreeValues(t, vals, 4);
+    }
 
+    {
+      t.erase(10);
+      int vals[] = {3, 4, 6, 8};
+      assertWTreeValues(t, vals, 4);
+    }
 
 
-    t = wtree<int>::insertUpdate(t, 3);
-    CPPUNIT_ASSERT(!t.empty());
-    CPPUNIT_ASSERT(t.size() == 4);
+    {
+      t.erase(-1);
+      int vals[] = {3, 4, 6, 8};
+      assertWTreeValues(t, vals, 4);
+    }
 
-    i = t.begin();
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 3);
+    {
+      t.erase(4);
+      int vals[] = {3, 6, 8};
+      assertWTreeValues(t, vals, 3);
+    }
 
-    ++i;
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 5);
+    {
+      t.erase(8);
+      int vals[] = {3, 6};
+      assertWTreeValues(t, vals, 2);
+    }
 
-    ++i;
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 7);
 
-    ++i;
+    {
+      t.erase(3);
+      int vals[] = {6};
+      assertWTreeValues(t, vals, 1);
+    }
 
-    CPPUNIT_ASSERT(i != t.end());
-    CPPUNIT_ASSERT(*i == 8);
 
-    ++i;
 
-    CPPUNIT_ASSERT(i == t.end());
+    {
+      t.erase(6);
+      int *vals = NULL;
+      assertWTreeValues(t, vals, 0);
+    }
   }
 };
 



More information about the Aptitude-svn-commit mailing list