From a388e2c1a49ccb238741e01b9a53aac0f1bf7795 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 15:48:18 -0500 Subject: [PATCH 1/6] treemap: rm a bit of redundant code --- src/libstd/treemap.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 82090f8dd62c7..938c4cc4ed534 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -652,14 +652,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(); } From 456af7a79da586a3c64d810a9157bba0616b6b53 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 15:53:03 -0500 Subject: [PATCH 2/6] update comments documenting issue #4492 workaround --- src/libstd/treemap.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index 938c4cc4ed534..ed06d6a34b58d 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -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(); @@ -967,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); @@ -982,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(); } From bfa9c9a00f0a301a5e936ae14c6a95e98f3bf5ee Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 16:07:11 -0500 Subject: [PATCH 3/6] add is_subset and is_superset to the Set trait --- src/libcore/container.rs | 6 ++++ src/libcore/hashmap.rs | 47 ++++++++++++++++++++++++- src/libstd/treemap.rs | 74 ++++++++++++++++++++-------------------- 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 272a2efc03553..669a41be2b79c 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -65,4 +65,10 @@ 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 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; } diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 4a3ee18440b05..a9f3cd5247c72 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -25,6 +25,7 @@ pub mod linear { use cmp::Eq; use cmp; use hash::Hash; + use iter; use kinds::Copy; use option::{None, Option, Some}; use option; @@ -453,6 +454,16 @@ 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 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) + } } pub impl LinearSet { @@ -462,7 +473,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 +621,37 @@ pub mod test { assert !m.is_empty(); } } + +#[test] +mod test_set { + use super::*; + + #[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); + } +} diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index ed06d6a34b58d..ece120bb6477e 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -291,6 +291,43 @@ 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) } + + /// Return true if the set is a subset of another + pure fn is_subset(&self, other: &TreeSet) -> bool { + other.is_superset(self) + } + + /// 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(); + unsafe { // purity workaround + x = x.next(); + y = y.next(); + let mut a = x.get(); + let mut b = y.get(); + 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) { + y = y.next(); + b = y.get(); + } + x = x.next(); + a = x.get(); + } + } + true + } } impl TreeSet { @@ -335,43 +372,6 @@ impl TreeSet { true } - /// Check of 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 - pure fn is_superset(&self, other: &TreeSet) -> bool { - let mut x = self.iter(); - let mut y = other.iter(); - unsafe { // purity workaround - x = x.next(); - y = y.next(); - let mut a = x.get(); - let mut b = y.get(); - 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) { - y = y.next(); - b = y.get(); - } - x = x.next(); - a = x.get(); - } - } - true - } - /// Visit the values (in-order) representing the difference pure fn difference(&self, other: &TreeSet, f: fn(&T) -> bool) { let mut x = self.iter(); From 42cafcee2c740c6d2a85018a947b78338d2afa8e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 17:04:25 -0500 Subject: [PATCH 4/6] add is_disjoint to the Set trait --- src/libcore/container.rs | 4 +++ src/libcore/hashmap.rs | 33 +++++++++++++++++++++--- src/libstd/treemap.rs | 54 ++++++++++++++++++++-------------------- 3 files changed, 61 insertions(+), 30 deletions(-) diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 669a41be2b79c..3c9ee50855e27 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -66,6 +66,10 @@ pub trait Set: Mutable { /// 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; diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index a9f3cd5247c72..cf99c0e46b976 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -14,16 +14,15 @@ #[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; @@ -455,6 +454,12 @@ pub mod linear { /// 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)) @@ -626,6 +631,28 @@ mod test_map { 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(); diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index ece120bb6477e..b1c22f86c96a5 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -292,6 +292,33 @@ impl TreeSet: Set { /// 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 { + let mut x = self.iter(); + let mut y = other.iter(); + unsafe { // purity workaround + x = x.next(); + y = y.next(); + let mut a = x.get(); + let mut b = y.get(); + while a.is_some() && b.is_some() { + let a1 = a.unwrap(); + let b1 = b.unwrap(); + if a1 < b1 { + x = x.next(); + a = x.get(); + } else if b1 < a1 { + y = y.next(); + b = y.get(); + } else { + return false; + } + } + } + true + } + /// Return true if the set is a subset of another pure fn is_subset(&self, other: &TreeSet) -> bool { other.is_superset(self) @@ -345,33 +372,6 @@ impl TreeSet { 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 { - let mut x = self.iter(); - let mut y = other.iter(); - unsafe { // purity workaround - x = x.next(); - y = y.next(); - let mut a = x.get(); - let mut b = y.get(); - while a.is_some() && b.is_some() { - let a1 = a.unwrap(); - let b1 = b.unwrap(); - if a1 < b1 { - x = x.next(); - a = x.get(); - } else if b1 < a1 { - y = y.next(); - b = y.get(); - } else { - return false; - } - } - } - true - } - /// Visit the values (in-order) representing the difference pure fn difference(&self, other: &TreeSet, f: fn(&T) -> bool) { let mut x = self.iter(); From 99eb4ddddd68e9ffa86eb8df264934925e27d737 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 19:30:26 -0500 Subject: [PATCH 5/6] add difference and symmetric_difference to Set --- src/libcore/container.rs | 6 ++++ src/libcore/hashmap.rs | 65 ++++++++++++++++++++++++++++++++++++++++ src/libstd/treemap.rs | 34 ++++++++++----------- 3 files changed, 88 insertions(+), 17 deletions(-) diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 3c9ee50855e27..15685ec672251 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -75,4 +75,10 @@ pub trait Set: Mutable { /// 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); } diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index cf99c0e46b976..5711c88e8907f 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -469,6 +469,22 @@ pub mod linear { 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); + } } pub impl LinearSet { @@ -681,4 +697,53 @@ mod test_set { assert !b.is_subset(&a); assert b.is_superset(&a); } + + #[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(); + } } diff --git a/src/libstd/treemap.rs b/src/libstd/treemap.rs index b1c22f86c96a5..235db26354293 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 { @@ -355,22 +355,6 @@ impl TreeSet: Set { } true } -} - -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()} - } /// Visit the values (in-order) representing the difference pure fn difference(&self, other: &TreeSet, f: fn(&T) -> bool) { @@ -448,6 +432,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()} + } /// Visit the values (in-order) representing the intersection pure fn intersection(&self, other: &TreeSet, f: fn(&T) -> bool) { From 6b08683e15f2765b03e9c7c3b6cff83b0cfd7b24 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 29 Jan 2013 21:58:47 -0500 Subject: [PATCH 6/6] add intersection and union to the Set trait --- src/libcore/container.rs | 6 +++ src/libcore/hashmap.rs | 84 +++++++++++++++++++++++++++++++++++++++- src/libstd/treemap.rs | 32 +++++++-------- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 15685ec672251..0a79a0ae19d96 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -81,4 +81,10 @@ pub trait Set: Mutable { /// 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 5711c88e8907f..bef1069eef1fe 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -474,7 +474,7 @@ pub mod linear { pure fn difference(&self, other: &LinearSet, f: fn(&T) -> bool) { for self.each |v| { if !other.contains(v) { - if !f(v) { return; } + if !f(v) { return } } } } @@ -485,6 +485,28 @@ pub mod linear { 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 { @@ -698,6 +720,36 @@ mod test_set { 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(); @@ -746,4 +798,34 @@ mod test_set { } 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 235db26354293..1105d65a4ed6f 100644 --- a/src/libstd/treemap.rs +++ b/src/libstd/treemap.rs @@ -432,22 +432,6 @@ impl TreeSet: Set { } } } -} - -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()} - } /// Visit the values (in-order) representing the intersection pure fn intersection(&self, other: &TreeSet, f: fn(&T) -> bool) { @@ -516,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