]> git.lizzy.rs Git - rust.git/commitdiff
hashmap: Iterators for hashset diff, sym. diff, intersec, union
authorblake2-ppc <blake2-ppc>
Tue, 16 Jul 2013 01:55:52 +0000 (03:55 +0200)
committerblake2-ppc <blake2-ppc>
Tue, 16 Jul 2013 02:09:41 +0000 (04:09 +0200)
Implement the difference, union, etc iterators with the help of a custom
iterator combinator with explicit closure environment. Reported issue #7814
to be able to use the std::iterator filter combinator.

src/libstd/hashmap.rs

index 0131c3b540a19b1170dfe02a41ea3a03454c1118..79c6c4fb21dcc21457017d38ee213be54768bd8b 100644 (file)
 #[mutable_doc];
 
 use container::{Container, Mutable, Map, MutableMap, Set, MutableSet};
+use clone::Clone;
 use cmp::{Eq, Equiv};
 use hash::Hash;
-use iterator::{Iterator, IteratorUtil, FromIterator};
+use iterator::{Iterator, IteratorUtil, FromIterator, ChainIterator};
 use num;
 use option::{None, Option, Some};
 use rand::RngUtil;
@@ -703,25 +704,24 @@ fn is_superset(&self, other: &HashSet<T>) -> bool {
 
     /// Visit the values representing the difference
     fn difference(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
-        self.iter().advance(|v| other.contains(v) || f(v))
+        self.difference_iter(other).advance(f)
     }
 
     /// Visit the values representing the symmetric difference
     fn symmetric_difference(&self,
                             other: &HashSet<T>,
                             f: &fn(&T) -> bool) -> bool {
-        self.difference(other, |t| f(t)) && other.difference(self, |t| f(t))
+        self.symmetric_difference_iter(other).advance(f)
     }
 
     /// Visit the values representing the intersection
     fn intersection(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
-        self.iter().advance(|v| !other.contains(v) || f(v))
+        self.intersection_iter(other).advance(f)
     }
 
     /// Visit the values representing the union
     fn union(&self, other: &HashSet<T>, f: &fn(&T) -> bool) -> bool {
-        self.iter().advance(|t| f(t)) &&
-            other.iter().advance(|v| self.contains(v) || f(v))
+        self.union_iter(other).advance(f)
     }
 }
 
@@ -776,6 +776,33 @@ pub fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool {
     pub fn iter<'a>(&'a self) -> HashSetIterator<'a, T> {
         HashSetIterator { iter: self.map.buckets.iter() }
     }
+
+    /// Visit the values representing the difference
+    pub fn difference_iter<'a>(&'a self, other: &'a HashSet<T>)
+        -> SetAlgebraIter<'a, T> {
+        EnvFilterIterator{iter: self.iter(), env: other,
+                          filter: |elt, other| !other.contains(elt) }
+    }
+
+    /// Visit the values representing the symmetric difference
+    pub fn symmetric_difference_iter<'a>(&'a self, other: &'a HashSet<T>)
+        -> ChainIterator<&'a T, SetAlgebraIter<'a, T>, SetAlgebraIter<'a, T>> {
+        self.difference_iter(other).chain_(other.difference_iter(self))
+    }
+
+    /// Visit the values representing the intersection
+    pub fn intersection_iter<'a>(&'a self, other: &'a HashSet<T>)
+        -> SetAlgebraIter<'a, T> {
+        EnvFilterIterator{iter: self.iter(), env: other,
+                          filter: |elt, other| other.contains(elt) }
+    }
+
+    /// Visit the values representing the union
+    pub fn union_iter<'a>(&'a self, other: &'a HashSet<T>)
+        -> ChainIterator<&'a T, HashSetIterator<'a, T>, SetAlgebraIter<'a, T>> {
+        self.iter().chain_(other.difference_iter(self))
+    }
+
 }
 
 impl<K: Eq + Hash, T: Iterator<K>> FromIterator<K, T> for HashSet<K> {
@@ -791,6 +818,39 @@ pub fn from_iterator(iter: &mut T) -> HashSet<K> {
     }
 }
 
+// FIXME #7814: use std::iterator::FilterIterator
+/// Building block for Set operation iterators
+pub struct EnvFilterIterator<A, Env, I> {
+    priv env: Env,
+    priv filter: &'static fn(&A, Env) -> bool,
+    priv iter: I,
+}
+
+impl<'self, A, Env: Clone, I: Iterator<&'self A>> Iterator<&'self A>
+        for EnvFilterIterator<A, Env, I> {
+    #[inline]
+    fn next(&mut self) -> Option<&'self A> {
+        loop {
+            match self.iter.next() {
+                Some(elt) => if (self.filter)(elt, self.env.clone()) {
+                    return Some(elt)
+                },
+                None => return None,
+            }
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        let (_, upper) = self.iter.size_hint();
+        (0, upper)
+    }
+}
+
+/// Set operations iterator
+pub type SetAlgebraIter<'self, T> =
+    EnvFilterIterator<T, &'self HashSet<T>, HashSetIterator<'self, T>>;
+
 
 #[cfg(test)]
 mod test_map {
@@ -1126,7 +1186,7 @@ fn test_intersection() {
 
         let mut i = 0;
         let expected = [3, 5, 11, 77];
-        for a.intersection(&b) |x| {
+        for a.intersection_iter(&b).advance |x| {
             assert!(expected.contains(x));
             i += 1
         }
@@ -1149,7 +1209,7 @@ fn test_difference() {
 
         let mut i = 0;
         let expected = [1, 5, 11];
-        for a.difference(&b) |x| {
+        for a.difference_iter(&b).advance |x| {
             assert!(expected.contains(x));
             i += 1
         }
@@ -1175,7 +1235,7 @@ fn test_symmetric_difference() {
 
         let mut i = 0;
         let expected = [-2, 1, 5, 11, 14, 22];
-        for a.symmetric_difference(&b) |x| {
+        for a.symmetric_difference_iter(&b).advance |x| {
             assert!(expected.contains(x));
             i += 1
         }
@@ -1205,7 +1265,7 @@ fn test_union() {
 
         let mut i = 0;
         let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24];
-        for a.union(&b) |x| {
+        for a.union_iter(&b).advance |x| {
             assert!(expected.contains(x));
             i += 1
         }