From 2733313f1d2e8f2e131ca2ce27f56299dd9c4385 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Jan 2013 10:27:26 -0500 Subject: [PATCH 01/22] replace treemap with a balanced tree --- src/libstd/treemap.rs | 794 +++++++++++++++++++++++++++++++++++------- 1 file changed, 667 insertions(+), 127 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index af3ab4b88eb68..35a6be135c70a 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -1,4 +1,4 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,187 +8,727 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! - * A key,value store that works on anything. - * - * This works using a binary search tree. In the first version, it's a - * very naive algorithm, but it will probably be updated to be a - * red-black tree or something else. - */ +//! An ordered map and set implemented as self-balancing binary search +//! trees. The only requirement for the types is that the key implements +//! `Ord`, and that the `lt` method provides a total ordering. + #[forbid(deprecated_mode)]; use core::cmp::{Eq, Ord}; use core::option::{Option, Some, None}; use core::prelude::*; -pub type TreeMap = @mut TreeEdge; +// This is implemented as an AA tree, which is a simplified variation of +// a red-black tree where where red (horizontal) nodes can only be added +// as a right child. The time complexity is the same, and re-balancing +// operations are more frequent but also cheaper. -type TreeEdge = Option<@TreeNode>; +// TODO: lazy iteration, for O(n) Eq and set operations instead of O(n*log(m)) -struct TreeNode { - key: K, - mut value: V, - mut left: TreeEdge, - mut right: TreeEdge -} - -/// Create a treemap -pub fn TreeMap() -> TreeMap { @mut None } - -/// Insert a value into the map -pub fn insert(m: &mut TreeEdge, k: K, v: V) { - match copy *m { - None => { - *m = Some(@TreeNode {key: k, - mut value: v, - mut left: None, - mut right: None}); - return; - } - Some(node) => { - if k == node.key { - node.value = v; - } else if k < node.key { - insert(&mut node.left, k, v); - } else { - insert(&mut node.right, k, v); +// TODO: implement Ord for TreeSet +// could be superset/subset-based or in-order lexicographic comparison... but +// there are methods for is_superset/is_subset so lexicographic is more useful + +// TODO: (possibly) implement the overloads Python does for sets: +// * union: | +// * intersection: & +// * difference: - +// * symmetric difference: ^ +// These would be convenient since the methods will work like `each` + +pub struct TreeMap { + priv root: Option<~TreeNode>, + priv length: uint +} + +// FIXME: this is a naive O(n*log(m)) implementation, could be O(n) +impl TreeMap: Eq { + pure fn eq(&self, other: &TreeMap) -> bool { + if self.len() != other.len() { + return false } - } - }; + for self.each |x, y| { + match other.find(x) { + Some(z) => if z != y { return false }, + None => return false + } + } + true + } + pure fn ne(&self, other: &TreeMap) -> bool { + !self.eq(other) + } } -/// Find a value based on the key -pub fn find(m: &const TreeEdge, k: K) - -> Option { - match copy *m { - None => None, +impl TreeMap { + /// Create an empty TreeMap + static pure fn new() -> TreeMap { TreeMap{root: None, length: 0} } - // FIXME (#2808): was that an optimization? - Some(node) => { - if k == node.key { - Some(node.value) - } else if k < node.key { - find(&const node.left, k) - } else { - find(&const node.right, k) + /// Return the number of elements in the map + pure fn len(&self) -> uint { self.length } + + /// Return true if the map contains no elements + pure fn is_empty(&self) -> bool { self.root.is_none() } + + /// Return true if the map contains some elements + pure fn is_not_empty(&self) -> bool { self.root.is_some() } + + /// Visit all key-value pairs in order + pure fn each(&self, f: fn(&K, &V) -> bool) { each(&self.root, f) } + + /// Visit all keys in order + pure fn each_key(&self, f: fn(&K) -> bool) { self.each(|k, _| f(k)) } + + /// Visit all values in order + pure fn each_value(&self, f: fn(&V) -> bool) { self.each(|_, v| f(v)) } + + /// Visit all key-value pairs in reverse order + pure fn each_reverse(&self, f: fn(&K, &V) -> bool) { + each_reverse(&self.root, f); + } + + /// Visit all keys in reverse order + pure fn each_key_reverse(&self, f: fn(&K) -> bool) { + self.each_reverse(|k, _| f(k)) + } + + /// Visit all values in reverse order + pure fn each_value_reverse(&self, f: fn(&V) -> bool) { + self.each_reverse(|_, v| f(v)) + } + + /// Return true if the map contains a value for the specified key + pure fn contains_key(&self, key: &K) -> bool { + self.find(key).is_some() + } + + /// Return the value corresponding to the key in the map + pure fn find(&self, key: &K) -> Option<&self/V> { + let mut current: &self/Option<~TreeNode> = &self.root; + loop { + match *current { + Some(ref r) => { + let r: &self/~TreeNode = r; // FIXME: #3148 + if *key < r.key { + current = &r.left; + } else if r.key < *key { + current = &r.right; + } else { + return Some(&r.value); + } + } + None => return None + } } - } + } + + /// Insert a key-value pair into the map. An existing value for a + /// key is replaced by the new value. Return true if the key did + /// not already exist in the map. + fn insert(&mut self, key: K, value: V) -> bool { + let ret = insert(&mut self.root, key, value); + if ret { self.length += 1 } + ret + } + + /// Remove a key-value pair from the map. Return true if the key + /// was present in the map, otherwise false. + fn remove(&mut self, key: &K) -> bool { + let ret = remove(&mut self.root, key); + if ret { self.length -= 1 } + ret } } -/// Visit all pairs in the map in order. -pub fn traverse(m: &const TreeEdge, - f: fn((&K), (&V))) { - match copy *m { - None => (), - Some(node) => { - traverse(&const node.left, f); - // copy of value is req'd as f() requires an immutable ptr - f(&node.key, © node.value); - traverse(&const node.right, f); - } +pub struct TreeSet { + priv map: TreeMap +} + +impl TreeSet: iter::BaseIter { + /// Visit all values in order + pure fn each(&self, f: fn(&T) -> bool) { self.map.each_key(f) } + pure fn size_hint(&self) -> Option { Some(self.len()) } +} + +impl TreeSet: Eq { + pure fn eq(&self, other: &TreeSet) -> bool { self.map == other.map } + pure fn ne(&self, other: &TreeSet) -> bool { self.map != other.map } +} + +impl TreeSet { + /// Create an empty TreeSet + static pure fn new() -> TreeSet { TreeSet{map: TreeMap::new()} } + + /// Return the number of elements in the set + pure fn len(&self) -> uint { self.map.len() } + + /// Return true if the set contains no elements + pure fn is_empty(&self) -> bool { self.map.is_empty() } + + /// Return true if the set contains some elements + pure fn is_not_empty(&self) -> bool { self.map.is_not_empty() } + + /// Visit all values in reverse order + pure fn each_reverse(&self, f: fn(&T) -> bool) { + self.map.each_key_reverse(f) + } + + /// Return true if the set contains a value + pure fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + + /// Add a value to the set. Return true if the value was not + /// already present in the set. + fn insert(&mut self, value: T) -> bool { self.map.insert(value, ()) } + + /// Remove a value from the set. Return true if the value was + /// present in the set. + fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } + + /// Return true if the set has no elements in common with `other`. + /// This is equivalent to checking for an empty intersection. + pure fn is_disjoint(&self, other: &TreeSet) -> bool { + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + !iter::any(self, |x| other.contains(x)) + } + + /// Check of the set is a subset of another + pure fn is_subset(&self, other: &TreeSet) -> bool { + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + !iter::any(self, |x| !other.contains(x)) + } + + /// Check of the set is a superset of another + pure fn is_superset(&self, other: &TreeSet) -> bool { + other.is_subset(self) + } + + /// Visit the values (in-order) representing the difference + pure fn difference(&self, _other: &TreeSet, + _f: fn(&T) -> bool) { + fail ~"not yet implemented" // TODO + } + + /// Visit the values (in-order) representing the symmetric difference + pure fn symmetric_difference(&self, _other: &TreeSet, + _f: fn(&T) -> bool) { + fail ~"not yet implemented" // TODO + } + + /// Visit the values (in-order) representing the intersection + pure fn intersection(&self, other: &TreeSet, + f: fn(&T) -> bool) { + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + for self.each |x| { + if other.contains(x) { + if !f(x) { break } + } + } + } + + /// Visit the values (in-order) representing the union + pure fn union(&self, _other: &TreeSet, _f: fn(&T) -> bool) -> TreeSet { + fail ~"not yet implemented" // TODO } } -/// Compare two treemaps and return true iff -/// they contain same keys and values -pub fn equals(t1: &const TreeEdge, - t2: &const TreeEdge) - -> bool { - let mut v1 = ~[]; - let mut v2 = ~[]; - traverse(t1, |k,v| { v1.push((copy *k, copy *v)) }); - traverse(t2, |k,v| { v2.push((copy *k, copy *v)) }); - return v1 == v2; +// Nodes keep track of their level in the tree, starting at 1 in the +// leaves and with a red child sharing the level of the parent. +struct TreeNode { + key: K, + value: V, + left: Option<~TreeNode>, + right: Option<~TreeNode>, + level: uint } +impl TreeNode { + #[inline(always)] + static pure fn new(key: K, value: V) -> TreeNode { + TreeNode{key: key, value: value, left: None, right: None, level: 1} + } +} -#[cfg(test)] -mod tests { - #[legacy_exports]; +pure fn each(node: &Option<~TreeNode>, + f: fn(&K, &V) -> bool) { + do node.map |x| { + each(&x.left, f); + if f(&x.key, &x.value) { each(&x.right, f) } + }; +} + +pure fn each_reverse(node: &Option<~TreeNode>, + f: fn(&K, &V) -> bool) { + do node.map |x| { + each_reverse(&x.right, f); + if f(&x.key, &x.value) { each_reverse(&x.left, f) } + }; +} + +// Remove left horizontal link by rotating right +fn skew(node: ~TreeNode) -> ~TreeNode { + if node.left.map_default(false, |x| x.level == node.level) { + let mut node = node; + let mut save = node.left.swap_unwrap(); + node.left <-> save.right; // save.right now None + save.right = Some(node); + save + } else { + node // nothing to do + } +} + +// Remove dual horizontal link by rotating left and increasing level of +// the parent +fn split(node: ~TreeNode) -> ~TreeNode { + if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) { + let mut node = node; + let mut save = node.right.swap_unwrap(); + node.right <-> save.left; // save.left now None + save.left = Some(node); + save.level += 1; + save + } else { + node // nothing to do + } +} + +fn insert(node: &mut Option<~TreeNode>, key: K, + value: V) -> bool { + if node.is_none() { + *node = Some(~TreeNode::new(key, value)); + true + } else { + let mut save = node.swap_unwrap(); + if key < save.key { + let inserted = insert(&mut save.left, key, value); + *node = Some(split(skew(save))); // re-balance, if necessary + inserted + } else if save.key < key { + let inserted = insert(&mut save.right, key, value); + *node = Some(split(skew(save))); // re-balance, if necessary + inserted + } else { + save.key = key; + save.value = value; + *node = Some(save); + false + } + } +} + +fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { + fn heir_swap(node: &mut TreeNode, + child: &mut Option<~TreeNode>) { + // *could* be done without recursion, but it won't borrow check + do child.mutate |child| { + let mut child = child; + if child.right.is_some() { + heir_swap(node, &mut child.right); + } else { + node.key <-> child.key; + node.value <-> child.value; + } + child + } + } + + if node.is_none() { + return false // bottom of tree + } else { + let mut save = node.swap_unwrap(); + + let removed = if save.key < *key { + remove(&mut save.right, key) + } else if *key < save.key { + remove(&mut save.left, key) + } else { + if save.left.is_some() { + if save.right.is_some() { + let mut left = save.left.swap_unwrap(); + if left.right.is_some() { + heir_swap(save, &mut left.right); + save.left = Some(left); + remove(&mut save.left, key); + } else { + save.key <-> left.key; + save.value <-> left.value; + save.left = Some(left); + remove(&mut save.left, key); + } + } else { + let mut rm = save.left.swap_unwrap(); + save.key <-> rm.key; + save.value <-> rm.value; + save.level <-> rm.level; // FIXME: may not be needed + save.left <-> rm.left; // FIXME: may not be needed + save.right <-> rm.right; // FIXME: may not be needed + } + } else if save.right.is_some() { + let mut rm = save.right.swap_unwrap(); + save.key <-> rm.key; + save.value <-> rm.value; + save.level <-> rm.level; // FIXME: may not be needed + save.left <-> rm.left; // FIXME: may not be needed + save.right <-> rm.right; // FIXME: may not be needed + } else { + return true // leaf + } + true + }; + + let left_level = save.left.map_default(0, |x| x.level); + let right_level = save.right.map_default(0, |x| x.level); + + // re-balance, if necessary + if left_level < save.level - 1 || right_level < save.level - 1 { + save.level -= 1; + + if right_level > save.level { + do save.right.mutate |x| { + let mut x = x; x.level = save.level; x + } + } + + save = skew(save); + + do save.right.mutate |right| { + let mut right = skew(right); + right.right.mutate(skew); + right + } + save = split(save); + save.right.mutate(split); + } - use treemap::*; + *node = Some(save); + removed + } +} - use core::option::{None, Option, Some}; +#[cfg(test)] +mod test_treemap { + use super::*; use core::str; #[test] - fn init_treemap() { let _m = TreeMap::(); } + fn find_empty() { + let m = TreeMap::new::(); assert m.find(&5) == None; + } #[test] - fn insert_one() { let m = TreeMap(); insert(m, 1, 2); } + fn find_not_found() { + let mut m = TreeMap::new(); + assert m.insert(1, 2); + assert m.insert(5, 3); + assert m.insert(9, 3); + assert m.find(&2) == None; + } #[test] - fn insert_two() { let m = TreeMap(); insert(m, 1, 2); insert(m, 3, 4); } + fn insert_replace() { + let mut m = TreeMap::new(); + assert m.insert(5, 2); + assert m.insert(2, 9); + assert !m.insert(2, 11); + assert m.find(&2).unwrap() == &11; + } #[test] - fn insert_find() { - let m = TreeMap(); - insert(m, 1, 2); - assert (find(m, 1) == Some(2)); + fn u8_map() { + let mut m = TreeMap::new(); + + let k1 = str::to_bytes(~"foo"); + let k2 = str::to_bytes(~"bar"); + let v1 = str::to_bytes(~"baz"); + let v2 = str::to_bytes(~"foobar"); + + m.insert(k1, v1); + m.insert(k2, v2); + + assert m.find(&k2) == Some(&v2); + assert m.find(&k1) == Some(&v1); + } + + fn check_equal(ctrl: &[(K, V)], map: &TreeMap) { + assert ctrl.is_empty() == map.is_empty(); + assert ctrl.is_not_empty() == map.is_not_empty(); + for ctrl.each |x| { + let &(k, v) = x; + assert map.find(&k).unwrap() == &v + } + for map.each |map_k, map_v| { + let mut found = false; + for ctrl.each |x| { + let &(ctrl_k, ctrl_v) = x; + if *map_k == ctrl_k { + assert *map_v == ctrl_v; + found = true; + break; + } + } + assert found; + } + } + + fn check_left(node: &Option<~TreeNode>, parent: &~TreeNode) { + match *node { + Some(ref r) => { + assert r.key < parent.key; + assert r.level == parent.level - 1; // left is black + check_left(&r.left, r); + check_right(&r.right, r, false); + } + None => assert parent.level == 1 // parent is leaf + } + } + + fn check_right(node: &Option<~TreeNode>, + parent: &~TreeNode, parent_red: bool) { + match *node { + Some(ref r) => { + assert r.key > parent.key; + let red = r.level == parent.level; + if parent_red { assert !red } // no dual horizontal links + assert red || r.level == parent.level - 1; // right is red or black + check_left(&r.left, r); + check_right(&r.right, r, red); + } + None => assert parent.level == 1 // parent is leaf + } + } + + fn check_structure(map: &TreeMap) { + match map.root { + Some(ref r) => { + check_left(&r.left, r); + check_right(&r.right, r, false); + } + None => () + } } #[test] - fn find_empty() { - let m = TreeMap::(); assert (find(m, 1) == None); + fn test_rand_int() { + let mut map = TreeMap::new::(); + let mut ctrl = ~[]; + + check_equal(ctrl, &map); + assert map.find(&5).is_none(); + + let rng = rand::seeded_rng(&~[42]); + + for 3.times { + for 90.times { + let k = rng.gen_int(); + let v = rng.gen_int(); + if !ctrl.contains(&(k, v)) { + assert map.insert(k, v); + ctrl.push((k, v)); + check_structure(&map); + check_equal(ctrl, &map); + } + } + + for 30.times { + let r = rng.gen_uint_range(0, ctrl.len()); + let (key, _) = vec::remove(&mut ctrl, r); + assert map.remove(&key); + check_structure(&map); + check_equal(ctrl, &map); + } + } } #[test] - fn find_not_found() { - let m = TreeMap(); - insert(m, 1, 2); - assert (find(m, 2) == None); + fn test_len() { + let mut m = TreeMap::new(); + assert m.insert(3, 6); + assert m.len() == 1; + assert m.insert(0, 0); + assert m.len() == 2; + assert m.insert(4, 8); + assert m.len() == 3; + assert m.remove(&3); + assert m.len() == 2; + assert !m.remove(&5); + assert m.len() == 2; + assert m.insert(2, 4); + assert m.len() == 3; + assert m.insert(1, 2); + assert m.len() == 4; + } + + #[test] + fn test_each() { + let mut m = TreeMap::new(); + + assert m.insert(3, 6); + assert m.insert(0, 0); + assert m.insert(4, 8); + assert m.insert(2, 4); + assert m.insert(1, 2); + + let mut n = 0; + for m.each |k, v| { + assert *k == n; + assert *v == n * 2; + n += 1; + } } #[test] - fn traverse_in_order() { - let m = TreeMap(); - insert(m, 3, ()); - insert(m, 0, ()); - insert(m, 4, ()); - insert(m, 2, ()); - insert(m, 1, ()); + fn test_each_reverse() { + let mut m = TreeMap::new(); + + assert m.insert(3, 6); + assert m.insert(0, 0); + assert m.insert(4, 8); + assert m.insert(2, 4); + assert m.insert(1, 2); - let n = @mut 0; - fn t(n: @mut int, k: int, _v: ()) { - assert (*n == k); *n += 1; + let mut n = 4; + for m.each_reverse |k, v| { + assert *k == n; + assert *v == n * 2; + n -= 1; } - traverse(m, |x,y| t(n, *x, *y)); } #[test] - fn equality() { - let m1 = TreeMap(); - insert(m1, 3, ()); - insert(m1, 0, ()); - insert(m1, 4, ()); - insert(m1, 2, ()); - insert(m1, 1, ()); - let m2 = TreeMap(); - insert(m2, 2, ()); - insert(m2, 1, ()); - insert(m2, 3, ()); - insert(m2, 0, ()); - insert(m2, 4, ()); + fn test_eq() { + let mut a = TreeMap::new(); + let mut b = TreeMap::new(); - assert equals(m1, m2); + assert a == b; + assert a.insert(0, 5); + assert a != b; + assert b.insert(0, 4); + assert a != b; + assert a.insert(5, 19); + assert a != b; + assert !b.insert(0, 5); + assert a != b; + assert b.insert(5, 19); + assert a == b; + } +} - let m3 = TreeMap(); - assert !equals(m1,m3); +#[cfg(test)] +mod test_set { + use super::*; + #[test] + fn test_disjoint() { + let mut xs = TreeSet::new(); + let mut ys = TreeSet::new(); + assert xs.is_disjoint(&ys); + assert ys.is_disjoint(&xs); + assert xs.insert(5); + assert ys.insert(11); + assert xs.is_disjoint(&ys); + assert ys.is_disjoint(&xs); + assert xs.insert(7); + assert xs.insert(19); + assert xs.insert(4); + assert ys.insert(2); + assert ys.insert(-11); + assert xs.is_disjoint(&ys); + assert ys.is_disjoint(&xs); + assert ys.insert(7); + assert !xs.is_disjoint(&ys); + assert !ys.is_disjoint(&xs); } #[test] - fn u8_map() { - let m = TreeMap(); + fn test_subset_and_superset() { + let mut a = TreeSet::new(); + assert a.insert(0); + assert a.insert(5); + assert a.insert(11); + assert a.insert(7); - let k1 = str::to_bytes(~"foo"); - let k2 = str::to_bytes(~"bar"); + let mut b = TreeSet::new(); + assert b.insert(0); + assert b.insert(7); + assert b.insert(19); + assert b.insert(250); + assert b.insert(11); + assert b.insert(200); + + assert !a.is_subset(&b); + assert !a.is_superset(&b); + assert !b.is_subset(&a); + assert !b.is_superset(&a); - insert(m, k1, ~"foo"); - insert(m, k2, ~"bar"); + assert b.insert(5); - assert (find(m, k2) == Some(~"bar")); - assert (find(m, k1) == Some(~"foo")); + assert a.is_subset(&b); + assert !a.is_superset(&b); + assert !b.is_subset(&a); + assert b.is_superset(&a); + } + + #[test] + fn test_each() { + let mut m = TreeSet::new(); + + assert m.insert(3); + assert m.insert(0); + assert m.insert(4); + assert m.insert(2); + assert m.insert(1); + + let mut n = 0; + for m.each |x| { + assert *x == n; + n += 1 + } + } + + #[test] + fn test_each_reverse() { + let mut m = TreeSet::new(); + + assert m.insert(3); + assert m.insert(0); + assert m.insert(4); + assert m.insert(2); + assert m.insert(1); + + let mut n = 4; + for m.each_reverse |x| { + assert *x == n; + n -= 1 + } + } + + #[test] + fn test_intersection() { + let mut a = TreeSet::new(); + let mut b = TreeSet::new(); + + a.insert(11); + a.insert(1); + a.insert(3); + a.insert(77); + a.insert(103); + a.insert(5); + a.insert(-5); + + b.insert(2); + b.insert(11); + b.insert(77); + b.insert(-9); + b.insert(-42); + b.insert(5); + b.insert(3); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for a.intersection(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); } } From a2b5d5524e09304d0872aa30d0086986515f4099 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Jan 2013 20:41:11 -0500 Subject: [PATCH 02/22] add a lazy forward iterator to TreeMap --- src/libstd/treemap.rs | 72 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 35a6be135c70a..858ebbf707327 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -23,8 +23,6 @@ use core::prelude::*; // as a right child. The time complexity is the same, and re-balancing // operations are more frequent but also cheaper. -// TODO: lazy iteration, for O(n) Eq and set operations instead of O(n*log(m)) - // TODO: implement Ord for TreeSet // could be superset/subset-based or in-order lexicographic comparison... but // there are methods for is_superset/is_subset so lexicographic is more useful @@ -138,8 +136,43 @@ impl TreeMap { if ret { self.length -= 1 } ret } + + /// Get a lazy iterator over the nodes in the map. Requires that it + /// be frozen (immutable). + fn iter(&self) -> TreeMapIterator/&self { + TreeMapIterator{stack: ~[], node: &self.root} + } +} + +/// Lazy forward iterator over a map +pub struct TreeMapIterator { + priv stack: ~[&~TreeNode], + priv node: &Option<~TreeNode> } +impl TreeMapIterator { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the key and value. If there are no + /// more nodes, return None. + fn next(&mut self) -> Option<(&self/K, &self/V)> { + while self.stack.is_not_empty() || self.node.is_some() { + match *self.node { + Some(ref x) => { + self.stack.push(x); + self.node = &x.left; + } + None => { + let res = self.stack.pop(); + self.node = &res.right; + return Some((&res.key, &res.value)); + } + } + } + None + } +} + + pub struct TreeSet { priv map: TreeMap } @@ -611,6 +644,41 @@ mod test_treemap { assert b.insert(5, 19); assert a == b; } + + #[test] + fn test_lazy_iterator() { + let mut m = TreeMap::new(); + let (x1, y1) = (2, 5); + let (x2, y2) = (9, 12); + let (x3, y3) = (20, -3); + let (x4, y4) = (29, 5); + let (x5, y5) = (103, 3); + + assert m.insert(x1, y1); + assert m.insert(x2, y2); + assert m.insert(x3, y3); + assert m.insert(x4, y4); + assert m.insert(x5, y5); + + let m = m; + let mut iter = m.iter(); + + // ICE: + //assert iter.next() == Some((&x1, &y1)); + //assert iter.next().eq(&Some((&x1, &y1))); + + assert iter.next().unwrap() == (&x1, &y1); + assert iter.next().unwrap() == (&x2, &y2); + assert iter.next().unwrap() == (&x3, &y3); + assert iter.next().unwrap() == (&x4, &y4); + assert iter.next().unwrap() == (&x5, &y5); + + // ICE: + //assert iter.next() == None; + //assert iter.next().eq(&None); + + assert iter.next().is_none(); + } } #[cfg(test)] From d96b79aef39e0ffa9eafd11d6e9f6985f28ff746 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Jan 2013 21:03:28 -0500 Subject: [PATCH 03/22] make Eq implementation O(n) --- src/libstd/treemap.rs | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 858ebbf707327..a954860a789b4 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -39,19 +39,26 @@ pub struct TreeMap { priv length: uint } -// FIXME: this is a naive O(n*log(m)) implementation, could be O(n) -impl TreeMap: Eq { +impl TreeMap: Eq { pure fn eq(&self, other: &TreeMap) -> bool { if self.len() != other.len() { return false } - for self.each |x, y| { - match other.find(x) { - Some(z) => if z != y { return false }, - None => return false + unsafe { // purity workaround + let mut x = self.iter(); + let mut y = other.iter(); + for self.len().times { + // ICE: x.next() != y.next() + + let (x1, x2) = x.next().unwrap(); + let (y1, y2) = y.next().unwrap(); + + if x1 != y1 || x2 != y2 { + return false + } } + true } - true } pure fn ne(&self, other: &TreeMap) -> bool { !self.eq(other) @@ -137,8 +144,8 @@ impl TreeMap { ret } - /// Get a lazy iterator over the nodes in the map. Requires that it - /// be frozen (immutable). + /// Get a lazy iterator over the key-value pairs in the map. + /// Requires that it be frozen (immutable). fn iter(&self) -> TreeMapIterator/&self { TreeMapIterator{stack: ~[], node: &self.root} } @@ -183,7 +190,7 @@ impl TreeSet: iter::BaseIter { pure fn size_hint(&self) -> Option { Some(self.len()) } } -impl TreeSet: Eq { +impl TreeSet: Eq { pure fn eq(&self, other: &TreeSet) -> bool { self.map == other.map } pure fn ne(&self, other: &TreeSet) -> bool { self.map != other.map } } From 68663159a9a7a2a7815375b0f69bbeb6fa26eda6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Jan 2013 21:12:49 -0500 Subject: [PATCH 04/22] clean up equality code a bit --- src/libstd/treemap.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index a954860a789b4..1f7b001918c12 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -42,9 +42,8 @@ pub struct TreeMap { impl TreeMap: Eq { pure fn eq(&self, other: &TreeMap) -> bool { if self.len() != other.len() { - return false - } - unsafe { // purity workaround + false + } else unsafe { // unsafe used as a purity workaround let mut x = self.iter(); let mut y = other.iter(); for self.len().times { From f486f00395b86bb143462051fd1cf7cea47f0d2c Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Jan 2013 21:13:39 -0500 Subject: [PATCH 05/22] rm extra newline --- src/libstd/treemap.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 1f7b001918c12..5fd58d28ab1b1 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -178,7 +178,6 @@ impl TreeMapIterator { } } - pub struct TreeSet { priv map: TreeMap } From 1a1039cd646f51283160cd10657a9b0eea135257 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 06:45:30 -0500 Subject: [PATCH 06/22] remove 'TODO' from the list of future improvements --- src/libstd/treemap.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 5fd58d28ab1b1..127c007a25f30 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -23,11 +23,13 @@ use core::prelude::*; // as a right child. The time complexity is the same, and re-balancing // operations are more frequent but also cheaper. -// TODO: implement Ord for TreeSet +// Future improvements: + +// implement Ord for TreeSet // could be superset/subset-based or in-order lexicographic comparison... but // there are methods for is_superset/is_subset so lexicographic is more useful -// TODO: (possibly) implement the overloads Python does for sets: +// (possibly) implement the overloads Python does for sets: // * union: | // * intersection: & // * difference: - From fcd8eb4de66cefbb43b1c32953a7d5dfc3d0a1c2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 07:05:41 -0500 Subject: [PATCH 07/22] fix API of union --- src/libstd/treemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 127c007a25f30..ee647862d965b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -266,7 +266,7 @@ impl TreeSet { } /// Visit the values (in-order) representing the union - pure fn union(&self, _other: &TreeSet, _f: fn(&T) -> bool) -> TreeSet { + pure fn union(&self, _other: &TreeSet, _f: fn(&T) -> bool) { fail ~"not yet implemented" // TODO } } From a6eb596e76ad61d942a0fa1447fc894ef0cab4a4 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 08:55:13 -0500 Subject: [PATCH 08/22] implement set difference --- src/libstd/treemap.rs | 64 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index ee647862d965b..fe3fe9888a31a 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -243,20 +243,46 @@ impl TreeSet { } /// Visit the values (in-order) representing the difference - pure fn difference(&self, _other: &TreeSet, - _f: fn(&T) -> bool) { - fail ~"not yet implemented" // TODO + pure fn difference(&self, other: &TreeSet, f: fn(&T) -> bool) { + unsafe { // purity workaround + let mut x = self.map.iter(); + let mut y = other.map.iter(); + + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + while a.is_some() { + let (a1, _) = a.unwrap(); + if !f(a1) { return } + a = x.next(); + } + return + } + + let (a1, _) = a.unwrap(); + let (b1, _) = b.unwrap(); + + if a1 < b1 { + if !f(a1) { return } + a = x.next(); + } else { + if !(b1 < a1) { a = x.next() } + b = y.next(); + } + } + } } /// Visit the values (in-order) representing the symmetric difference pure fn symmetric_difference(&self, _other: &TreeSet, _f: fn(&T) -> bool) { - fail ~"not yet implemented" // TODO + fail ~"not yet implemented" } /// Visit the values (in-order) representing the intersection - pure fn intersection(&self, other: &TreeSet, - f: fn(&T) -> bool) { + pure fn intersection(&self, other: &TreeSet, f: fn(&T) -> bool) { // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) for self.each |x| { if other.contains(x) { @@ -267,7 +293,7 @@ impl TreeSet { /// Visit the values (in-order) representing the union pure fn union(&self, _other: &TreeSet, _f: fn(&T) -> bool) { - fail ~"not yet implemented" // TODO + fail ~"not yet implemented" } } @@ -806,4 +832,28 @@ mod test_set { } assert i == expected.len(); } + + #[test] + fn test_difference() { + let mut a = TreeSet::new(); + let mut b = TreeSet::new(); + + a.insert(1); + a.insert(3); + a.insert(5); + a.insert(9); + a.insert(11); + + b.insert(3); + b.insert(9); + + let mut i = 0; + let expected = [1, 5, 11]; + for a.difference(&b) |x| { + io::println(fmt!("%?", x)); + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } } From 2b63d7e3475953513210899f57a8dd79753536ae Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 09:50:51 -0500 Subject: [PATCH 09/22] range search would be nice --- src/libstd/treemap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index fe3fe9888a31a..44345bdd853aa 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -25,6 +25,8 @@ use core::prelude::*; // Future improvements: +// range search - O(log n) retrieval of an iterator from some key + // implement Ord for TreeSet // could be superset/subset-based or in-order lexicographic comparison... but // there are methods for is_superset/is_subset so lexicographic is more useful From 44b444e6918b6648c03e8c74c96055c812cec1f2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 09:58:52 -0500 Subject: [PATCH 10/22] add scaffolding for symmetric_difference/union --- src/libstd/treemap.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 44345bdd853aa..9ebb760358b4b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -229,13 +229,13 @@ impl TreeSet { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. pure fn is_disjoint(&self, other: &TreeSet) -> bool { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) !iter::any(self, |x| other.contains(x)) } /// Check of the set is a subset of another pure fn is_subset(&self, other: &TreeSet) -> bool { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) !iter::any(self, |x| !other.contains(x)) } @@ -278,14 +278,21 @@ impl TreeSet { } /// Visit the values (in-order) representing the symmetric difference - pure fn symmetric_difference(&self, _other: &TreeSet, + pure fn symmetric_difference(&self, other: &TreeSet, _f: fn(&T) -> bool) { + unsafe { // purity workaround + let mut x = self.map.iter(); + let mut y = other.map.iter(); + + let mut a = x.next(); + let mut b = y.next(); + } fail ~"not yet implemented" } /// Visit the values (in-order) representing the intersection pure fn intersection(&self, other: &TreeSet, f: fn(&T) -> bool) { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n) + // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) for self.each |x| { if other.contains(x) { if !f(x) { break } @@ -294,7 +301,14 @@ impl TreeSet { } /// Visit the values (in-order) representing the union - pure fn union(&self, _other: &TreeSet, _f: fn(&T) -> bool) { + pure fn union(&self, other: &TreeSet, _f: fn(&T) -> bool) { + unsafe { // purity workaround + let mut x = self.map.iter(); + let mut y = other.map.iter(); + + let mut a = x.next(); + let mut b = y.next(); + } fail ~"not yet implemented" } } From fdb54fc9c29649c1daa14cd783024d58c357110f Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 10:10:38 -0500 Subject: [PATCH 11/22] make TreeSet tests a bit more paranoid --- src/libstd/treemap.rs | 44 +++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 9ebb760358b4b..34f2c05021fe9 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -824,21 +824,21 @@ mod test_set { let mut a = TreeSet::new(); let mut b = TreeSet::new(); - a.insert(11); - a.insert(1); - a.insert(3); - a.insert(77); - a.insert(103); - a.insert(5); - a.insert(-5); - - b.insert(2); - b.insert(11); - b.insert(77); - b.insert(-9); - b.insert(-42); - b.insert(5); - b.insert(3); + assert a.insert(11); + assert a.insert(1); + assert a.insert(3); + assert a.insert(77); + assert a.insert(103); + assert a.insert(5); + assert a.insert(-5); + + assert b.insert(2); + assert b.insert(11); + assert b.insert(77); + assert b.insert(-9); + assert b.insert(-42); + assert b.insert(5); + assert b.insert(3); let mut i = 0; let expected = [3, 5, 11, 77]; @@ -854,14 +854,14 @@ mod test_set { let mut a = TreeSet::new(); let mut b = TreeSet::new(); - a.insert(1); - a.insert(3); - a.insert(5); - a.insert(9); - a.insert(11); + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); - b.insert(3); - b.insert(9); + assert b.insert(3); + assert b.insert(9); let mut i = 0; let expected = [1, 5, 11]; From 63bc57fca8e3d9c8a9298dcdc158c7e1ff118e00 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 10:21:45 -0500 Subject: [PATCH 12/22] implement set union --- src/libstd/treemap.rs | 57 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 34f2c05021fe9..102949797b11b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -301,15 +301,38 @@ impl TreeSet { } /// Visit the values (in-order) representing the union - pure fn union(&self, other: &TreeSet, _f: fn(&T) -> bool) { + pure fn union(&self, other: &TreeSet, f: fn(&T) -> bool) { unsafe { // purity workaround let mut x = self.map.iter(); let mut y = other.map.iter(); let mut a = x.next(); let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + while a.is_some() { + let (a1, _) = a.unwrap(); + if !f(a1) { return } + a = x.next(); + } + } + + let (a1, _) = a.unwrap(); + let (b1, _) = b.unwrap(); + + if b1 < a1 { + if !f(b1) { return } + b = y.next(); + } else { + if !f(a1) { return } + if !(a1 < b1) { + b = y.next() + } + a = x.next(); + } + } } - fail ~"not yet implemented" } } @@ -866,7 +889,35 @@ mod test_set { let mut i = 0; let expected = [1, 5, 11]; for a.difference(&b) |x| { - io::println(fmt!("%?", x)); + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_union() { + let mut a = TreeSet::new(); + let mut b = TreeSet::new(); + + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); + assert a.insert(16); + assert a.insert(19); + + assert b.insert(-2); + assert b.insert(1); + assert b.insert(5); + assert b.insert(9); + assert b.insert(13); + assert b.insert(19); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19]; + for a.union(&b) |x| { assert *x == expected[i]; i += 1 } From 84469863ea7e1bcd3611c8d7b5546ba82cbd3f08 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 11:41:47 -0500 Subject: [PATCH 13/22] implement symmetric_difference --- src/libstd/treemap.rs | 60 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 102949797b11b..dca54abdfeec9 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -279,15 +279,45 @@ impl TreeSet { /// Visit the values (in-order) representing the symmetric difference pure fn symmetric_difference(&self, other: &TreeSet, - _f: fn(&T) -> bool) { + f: fn(&T) -> bool) { unsafe { // purity workaround let mut x = self.map.iter(); let mut y = other.map.iter(); let mut a = x.next(); let mut b = y.next(); + + while a.is_some() { + if b.is_none() { + while a.is_some() { + let (a1, _) = a.unwrap(); + if !f(a1) { return } + a = x.next(); + } + return + } + + let (a1, _) = a.unwrap(); + let (b1, _) = b.unwrap(); + + if a1 < b1 { + if !f(a1) { return } + a = x.next(); + } else { + if b1 < a1 { + if !f(b1) { return } + } else { + a = x.next(); + } + b = y.next(); + } + } + while b.is_some() { + let (b1, _) = b.unwrap(); + if !f(b1) { return } + b = y.next(); + } } - fail ~"not yet implemented" } /// Visit the values (in-order) representing the intersection @@ -895,6 +925,32 @@ mod test_set { assert i == expected.len(); } + #[test] + fn test_symmetric_difference() { + let mut a = TreeSet::new(); + let mut b = TreeSet::new(); + + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); + + assert b.insert(-2); + assert b.insert(3); + assert b.insert(9); + assert b.insert(14); + assert b.insert(22); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for a.symmetric_difference(&b) |x| { + assert *x == expected[i]; + i += 1 + } + assert i == expected.len(); + } + #[test] fn test_union() { let mut a = TreeSet::new(); From 7b7ffd960f2a6b9cab78366ef3c860e4df907983 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 12:19:17 -0500 Subject: [PATCH 14/22] fix bug in union implementation (missing return) --- src/libstd/treemap.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index dca54abdfeec9..6b0acaecaae2b 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -346,6 +346,7 @@ impl TreeSet { if !f(a1) { return } a = x.next(); } + return } let (a1, _) = a.unwrap(); @@ -963,6 +964,7 @@ mod test_set { assert a.insert(11); assert a.insert(16); assert a.insert(19); + assert a.insert(24); assert b.insert(-2); assert b.insert(1); @@ -972,7 +974,7 @@ mod test_set { assert b.insert(19); let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19]; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; for a.union(&b) |x| { assert *x == expected[i]; i += 1 From 240cc972c8e1d2ad57d3fd5d62e230a06ec92ec5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 12:44:43 -0500 Subject: [PATCH 15/22] docstring/comment fixes --- src/libstd/treemap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 6b0acaecaae2b..81e5aa1792802 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -36,7 +36,7 @@ use core::prelude::*; // * intersection: & // * difference: - // * symmetric difference: ^ -// These would be convenient since the methods will work like `each` +// These would be convenient since the methods work like `each` pub struct TreeMap { priv root: Option<~TreeNode>, @@ -163,7 +163,7 @@ pub struct TreeMapIterator { impl TreeMapIterator { /// Advance the iterator to the next node (in order) and return a /// tuple with a reference to the key and value. If there are no - /// more nodes, return None. + /// more nodes, return `None`. fn next(&mut self) -> Option<(&self/K, &self/V)> { while self.stack.is_not_empty() || self.node.is_some() { match *self.node { From b027ac3bb04dd51c750a4cbd48d7f849d88c409d Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 14:25:37 -0500 Subject: [PATCH 16/22] add TreeSetIterator --- src/libstd/treemap.rs | 83 ++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 81e5aa1792802..7e75b600bd76d 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -47,10 +47,10 @@ impl TreeMap: Eq { pure fn eq(&self, other: &TreeMap) -> bool { if self.len() != other.len() { false - } else unsafe { // unsafe used as a purity workaround + } else { let mut x = self.iter(); let mut y = other.iter(); - for self.len().times { + for self.len().times unsafe { // unsafe used as a purity workaround // ICE: x.next() != y.next() let (x1, x2) = x.next().unwrap(); @@ -149,7 +149,7 @@ impl TreeMap { /// Get a lazy iterator over the key-value pairs in the map. /// Requires that it be frozen (immutable). - fn iter(&self) -> TreeMapIterator/&self { + pure fn iter(&self) -> TreeMapIterator/&self { TreeMapIterator{stack: ~[], node: &self.root} } } @@ -226,6 +226,12 @@ impl TreeSet { /// present in the set. fn remove(&mut self, value: &T) -> bool { self.map.remove(value) } + /// Get a lazy iterator over the values in the set. + /// Requires that it be frozen (immutable). + pure fn iter(&self) -> TreeSetIterator/&self { + TreeSetIterator{iter: self.map.iter()} + } + /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. pure fn is_disjoint(&self, other: &TreeSet) -> bool { @@ -246,25 +252,22 @@ impl TreeSet { /// Visit the values (in-order) representing the difference pure fn difference(&self, other: &TreeSet, f: fn(&T) -> bool) { - unsafe { // purity workaround - let mut x = self.map.iter(); - let mut y = other.map.iter(); + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround let mut a = x.next(); let mut b = y.next(); while a.is_some() { if b.is_none() { - while a.is_some() { - let (a1, _) = a.unwrap(); - if !f(a1) { return } - a = x.next(); + return do a.while_some() |a1| { + if f(a1) { x.next() } else { None } } - return } - let (a1, _) = a.unwrap(); - let (b1, _) = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); if a1 < b1 { if !f(a1) { return } @@ -280,25 +283,22 @@ impl TreeSet { /// Visit the values (in-order) representing the symmetric difference pure fn symmetric_difference(&self, other: &TreeSet, f: fn(&T) -> bool) { - unsafe { // purity workaround - let mut x = self.map.iter(); - let mut y = other.map.iter(); + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround let mut a = x.next(); let mut b = y.next(); while a.is_some() { if b.is_none() { - while a.is_some() { - let (a1, _) = a.unwrap(); - if !f(a1) { return } - a = x.next(); + return do a.while_some() |a1| { + if f(a1) { x.next() } else { None } } - return } - let (a1, _) = a.unwrap(); - let (b1, _) = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); if a1 < b1 { if !f(a1) { return } @@ -312,10 +312,8 @@ impl TreeSet { b = y.next(); } } - while b.is_some() { - let (b1, _) = b.unwrap(); - if !f(b1) { return } - b = y.next(); + do b.while_some |b1| { + if f(b1) { y.next() } else { None } } } } @@ -332,25 +330,22 @@ impl TreeSet { /// Visit the values (in-order) representing the union pure fn union(&self, other: &TreeSet, f: fn(&T) -> bool) { - unsafe { // purity workaround - let mut x = self.map.iter(); - let mut y = other.map.iter(); + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround let mut a = x.next(); let mut b = y.next(); while a.is_some() { if b.is_none() { - while a.is_some() { - let (a1, _) = a.unwrap(); - if !f(a1) { return } - a = x.next(); + return do a.while_some() |a1| { + if f(a1) { x.next() } else { None } } - return } - let (a1, _) = a.unwrap(); - let (b1, _) = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); if b1 < a1 { if !f(b1) { return } @@ -367,6 +362,20 @@ impl TreeSet { } } +/// Lazy forward iterator over a set +pub struct TreeSetIterator { + priv iter: TreeMapIterator +} + +impl TreeSetIterator { + /// Advance the iterator to the next node (in order) and return a + /// tuple with a reference to the value. If there are no more nodes, + /// return `None`. + fn next(&mut self) -> Option<&self/T> { + self.iter.next().map_consume(|(x, _)| x) + } +} + // Nodes keep track of their level in the tree, starting at 1 in the // leaves and with a red child sharing the level of the parent. struct TreeNode { From 9119d5663d1cd4cf5772e915baef5e980f81f896 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 15:34:46 -0500 Subject: [PATCH 17/22] cleanup --- src/libstd/treemap.rs | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 7e75b600bd76d..f8abdaac27978 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -50,7 +50,7 @@ impl TreeMap: Eq { } else { let mut x = self.iter(); let mut y = other.iter(); - for self.len().times unsafe { // unsafe used as a purity workaround + for self.len().times unsafe { // unsafe as a purity workaround // ICE: x.next() != y.next() let (x1, x2) = x.next().unwrap(); @@ -216,7 +216,9 @@ impl TreeSet { } /// Return true if the set contains a value - pure fn contains(&self, value: &T) -> bool { self.map.contains_key(value) } + pure fn contains(&self, value: &T) -> bool { + self.map.contains_key(value) + } /// Add a value to the set. Return true if the value was not /// already present in the set. @@ -425,7 +427,8 @@ fn skew(node: ~TreeNode) -> ~TreeNode { // Remove dual horizontal link by rotating left and increasing level of // the parent fn split(node: ~TreeNode) -> ~TreeNode { - if node.right.map_default(false, |x| x.right.map_default(false, |y| y.level == node.level)) { + if node.right.map_default(false, + |x| x.right.map_default(false, |y| y.level == node.level)) { let mut node = node; let mut save = node.right.swap_unwrap(); node.right <-> save.left; // save.left now None @@ -501,20 +504,10 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { remove(&mut save.left, key); } } else { - let mut rm = save.left.swap_unwrap(); - save.key <-> rm.key; - save.value <-> rm.value; - save.level <-> rm.level; // FIXME: may not be needed - save.left <-> rm.left; // FIXME: may not be needed - save.right <-> rm.right; // FIXME: may not be needed + save = save.left.swap_unwrap(); } } else if save.right.is_some() { - let mut rm = save.right.swap_unwrap(); - save.key <-> rm.key; - save.value <-> rm.value; - save.level <-> rm.level; // FIXME: may not be needed - save.left <-> rm.left; // FIXME: may not be needed - save.right <-> rm.right; // FIXME: may not be needed + save = save.right.swap_unwrap(); } else { return true // leaf } @@ -615,7 +608,8 @@ mod test_treemap { } } - fn check_left(node: &Option<~TreeNode>, parent: &~TreeNode) { + fn check_left(node: &Option<~TreeNode>, + parent: &~TreeNode) { match *node { Some(ref r) => { assert r.key < parent.key; @@ -634,7 +628,7 @@ mod test_treemap { assert r.key > parent.key; let red = r.level == parent.level; if parent_red { assert !red } // no dual horizontal links - assert red || r.level == parent.level - 1; // right is red or black + assert red || r.level == parent.level - 1; // right red or black check_left(&r.left, r); check_right(&r.right, r, red); } From f20eab35c5c5250daf36d0f8a8b8795e1edab6fc Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 15:55:27 -0500 Subject: [PATCH 18/22] make is_disjoint O(n+m) instead of O(n*log(m)) --- src/libstd/treemap.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index f8abdaac27978..686a2bf9b2347 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -237,8 +237,24 @@ impl TreeSet { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. pure fn is_disjoint(&self, other: &TreeSet) -> bool { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) - !iter::any(self, |x| other.contains(x)) + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() && b.is_some() { + let a1 = a.unwrap(); + let b1 = b.unwrap(); + if a1 < b1 { + a = x.next(); + } else if b1 < a1 { + b = y.next(); + } else { + return false; + } + } + } + true } /// Check of the set is a subset of another From 698b93bedb1ec57ee2e36fa4fca4eac6d6ff6908 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 16:23:20 -0500 Subject: [PATCH 19/22] make intersection O(n+m) instead of O(n*log(m)) --- src/libstd/treemap.rs | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 686a2bf9b2347..1524a7ce4dc0f 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -338,10 +338,24 @@ impl TreeSet { /// Visit the values (in-order) representing the intersection pure fn intersection(&self, other: &TreeSet, f: fn(&T) -> bool) { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) - for self.each |x| { - if other.contains(x) { - if !f(x) { break } + let mut x = self.iter(); + let mut y = other.iter(); + + unsafe { // purity workaround + let mut a = x.next(); + let mut b = y.next(); + + while a.is_some() && b.is_some() { + let a1 = a.unwrap(); + let b1 = b.unwrap(); + if a1 < b1 { + a = x.next(); + } else { + if !(b1 < a1) { + if !f(a1) { return } + } + b = y.next(); + } } } } From 90469e2d72f1b80e8039061c396df8c3ebf8bcde Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Jan 2013 16:31:35 -0500 Subject: [PATCH 20/22] make is_superset/is_subset O(n+m) instead of O(n*log(m)) --- src/libstd/treemap.rs | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 1524a7ce4dc0f..1bba21c3e6281 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -259,13 +259,35 @@ impl TreeSet { /// Check of the set is a subset of another pure fn is_subset(&self, other: &TreeSet) -> bool { - // FIXME: this is a naive O(n*log(m)) implementation, could be O(n + m) - !iter::any(self, |x| !other.contains(x)) + other.is_superset(self) } /// Check of the set is a superset of another pure fn is_superset(&self, other: &TreeSet) -> bool { - other.is_subset(self) + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround + let mut a = x.next(); + let mut b = y.next(); + while b.is_some() { + if a.is_none() { + return false + } + + let a1 = a.unwrap(); + let b1 = b.unwrap(); + + if b1 < a1 { + return false + } + + if !(a1 < b1) { + b = y.next(); + } + a = x.next(); + } + } + true } /// Visit the values (in-order) representing the difference From c1ec6360fa5dcdb324d5f8ba0a2bf6c00298bbb7 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 17 Jan 2013 17:30:10 -0500 Subject: [PATCH 21/22] indentation fix --- src/libstd/treemap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 1bba21c3e6281..ed7a216193f2f 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -168,8 +168,8 @@ impl TreeMapIterator { while self.stack.is_not_empty() || self.node.is_some() { match *self.node { Some(ref x) => { - self.stack.push(x); - self.node = &x.left; + self.stack.push(x); + self.node = &x.left; } None => { let res = self.stack.pop(); From f042f58dbceff6c80519b1ec72bb4d38c65e1ab9 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 17 Jan 2013 19:05:23 -0500 Subject: [PATCH 22/22] re-borrow in heir_swap (fixes compile) --- src/libstd/treemap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index ed7a216193f2f..b5f60a66978e6 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -523,7 +523,7 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { do child.mutate |child| { let mut child = child; if child.right.is_some() { - heir_swap(node, &mut child.right); + heir_swap(&mut *node, &mut child.right); } else { node.key <-> child.key; node.value <-> child.value;