diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 272a2efc035..0a79a0ae19d 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -65,4 +65,26 @@ pub trait Set: Mutable { /// Remove a value from the set. Return true if the value was /// present in the set. fn remove(&mut self, value: &T) -> bool; + + /// 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: &self) -> bool; + + /// Return true if the set is a subset of another + pure fn is_subset(&self, other: &self) -> bool; + + /// Return true if the set is a superset of another + pure fn is_superset(&self, other: &self) -> bool; + + /// Visit the values representing the difference + pure fn difference(&self, other: &self, f: fn(&T) -> bool); + + /// Visit the values representing the symmetric difference + pure fn symmetric_difference(&self, other: &self, f: fn(&T) -> bool); + + /// Visit the values representing the intersection + pure fn intersection(&self, other: &self, f: fn(&T) -> bool); + + /// Visit the values representing the union + pure fn union(&self, other: &self, f: fn(&T) -> bool); } diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 4a3ee18440b..bef1069eef1 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -14,17 +14,17 @@ #[forbid(deprecated_mode)]; #[forbid(deprecated_pattern)]; +use container::{Container, Mutable, Map, Set}; use cmp::Eq; use hash::Hash; use to_bytes::IterBytes; /// Open addressing with linear probing. pub mod linear { + use super::*; use iter::BaseIter; - use container::{Container, Mutable, Map, Set}; - use cmp::Eq; - use cmp; use hash::Hash; + use iter; use kinds::Copy; use option::{None, Option, Some}; use option; @@ -453,6 +453,60 @@ pub mod linear { /// 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: &LinearSet) -> bool { + iter::all(self, |v| !other.contains(v)) + } + + /// Return true if the set is a subset of another + pure fn is_subset(&self, other: &LinearSet) -> bool { + iter::all(self, |v| other.contains(v)) + } + + /// Return true if the set is a superset of another + pure fn is_superset(&self, other: &LinearSet) -> bool { + other.is_subset(self) + } + + /// Visit the values representing the difference + pure fn difference(&self, other: &LinearSet, f: fn(&T) -> bool) { + for self.each |v| { + if !other.contains(v) { + if !f(v) { return } + } + } + } + + /// Visit the values representing the symmetric difference + pure fn symmetric_difference(&self, other: &LinearSet, + f: fn(&T) -> bool) { + self.difference(other, f); + other.difference(self, f); + } + + /// Visit the values representing the intersection + pure fn intersection(&self, other: &LinearSet, f: fn(&T) -> bool) { + for self.each |v| { + if other.contains(v) { + if !f(v) { return } + } + } + } + + /// Visit the values representing the union + pure fn union(&self, other: &LinearSet, f: fn(&T) -> bool) { + for self.each |v| { + if !f(v) { return } + } + + for other.each |v| { + if !self.contains(v) { + if !f(v) { return } + } + } + } } pub impl LinearSet { @@ -462,7 +516,7 @@ pub mod linear { } #[test] -pub mod test { +mod test_map { use container::{Container, Mutable, Map, Set}; use option::{None, Some}; use hashmap::linear::LinearMap; @@ -610,3 +664,168 @@ pub mod test { assert !m.is_empty(); } } + +#[test] +mod test_set { + use super::*; + + #[test] + fn test_disjoint() { + let mut xs = linear::LinearSet::new(); + let mut ys = linear::LinearSet::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 test_subset_and_superset() { + let mut a = linear::LinearSet::new(); + assert a.insert(0); + assert a.insert(5); + assert a.insert(11); + assert a.insert(7); + + let mut b = linear::LinearSet::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); + + assert b.insert(5); + + assert a.is_subset(&b); + assert !a.is_superset(&b); + assert !b.is_subset(&a); + assert b.is_superset(&a); + } + + #[test] + fn test_intersection() { + let mut a = linear::LinearSet::new(); + let mut b = linear::LinearSet::new(); + + 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]; + for a.intersection(&b) |x| { + assert vec::contains(expected, x); + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_difference() { + let mut a = linear::LinearSet::new(); + let mut b = linear::LinearSet::new(); + + assert a.insert(1); + assert a.insert(3); + assert a.insert(5); + assert a.insert(9); + assert a.insert(11); + + assert b.insert(3); + assert b.insert(9); + + let mut i = 0; + let expected = [1, 5, 11]; + for a.difference(&b) |x| { + assert vec::contains(expected, x); + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_symmetric_difference() { + let mut a = linear::LinearSet::new(); + let mut b = linear::LinearSet::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 vec::contains(expected, x); + i += 1 + } + assert i == expected.len(); + } + + #[test] + fn test_union() { + let mut a = linear::LinearSet::new(); + let mut b = linear::LinearSet::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 a.insert(24); + + 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, 24]; + for a.union(&b) |x| { + assert vec::contains(expected, x); + i += 1 + } + assert i == expected.len(); + } +} diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 82090f8dd62..1105d65a4ed 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -29,10 +29,10 @@ use core::prelude::*; // range search - O(log n) retrieval of an iterator from some key // (possibly) implement the overloads Python does for sets: -// * union: | // * intersection: & // * difference: - // * symmetric difference: ^ +// * union: | // These would be convenient since the methods work like `each` pub struct TreeMap { @@ -49,10 +49,9 @@ impl TreeMap: Eq { let mut y = other.iter(); for self.len().times { unsafe { // unsafe as a purity workaround - // ICE: x.next() != y.next() - x = x.next(); y = y.next(); + // FIXME: #4492 (ICE), x.get() == y.get() let (x1, x2) = x.get().unwrap(); let (y1, y2) = y.get().unwrap(); @@ -292,22 +291,6 @@ impl TreeSet: Set { /// 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) } -} - -impl TreeSet { - /// Create an empty TreeSet - static pure fn new() -> TreeSet { TreeSet{map: TreeMap::new()} } - - /// Visit all values in reverse order - pure fn each_reverse(&self, f: fn(&T) -> bool) { - self.map.each_key_reverse(f) - } - - /// 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. @@ -336,12 +319,12 @@ impl TreeSet { true } - /// Check of the set is a subset of another + /// Return true if the set is a subset of another pure fn is_subset(&self, other: &TreeSet) -> bool { other.is_superset(self) } - /// Check of the set is a superset of another + /// Return true if the set is a superset of another pure fn is_superset(&self, other: &TreeSet) -> bool { let mut x = self.iter(); let mut y = other.iter(); @@ -517,6 +500,22 @@ impl TreeSet { } } +impl TreeSet { + /// Create an empty TreeSet + static pure fn new() -> TreeSet { TreeSet{map: TreeMap::new()} } + + /// Visit all values in reverse order + pure fn each_reverse(&self, f: fn(&T) -> bool) { + self.map.each_key_reverse(f) + } + + /// 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()} + } +} + /// Lazy forward iterator over a set pub struct TreeSetIterator { priv iter: TreeMapIterator @@ -652,14 +651,12 @@ fn remove(node: &mut Option<~TreeNode>, key: &K) -> bool { 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); } + save.left = Some(left); + remove(&mut save.left, key); } else { save = save.left.swap_unwrap(); } @@ -969,9 +966,7 @@ mod test_treemap { let m = m; let mut iter = m.iter(); - // ICE: - //assert iter.next() == Some((&x1, &y1)); - //assert iter.next().eq(&Some((&x1, &y1))); + // FIXME: #4492 (ICE): iter.next() == Some((&x1, &y1)) iter = iter.next(); assert iter.get().unwrap() == (&x1, &y1); @@ -984,10 +979,6 @@ mod test_treemap { iter = iter.next(); assert iter.get().unwrap() == (&x5, &y5); - // ICE: - //assert iter.next() == None; - //assert iter.next().eq(&None); - iter = iter.next(); assert iter.get().is_none(); }