[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