From bcb527467245aedf5fe98f77e2607dc1e57df530 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:05 +0200 Subject: [PATCH 1/5] std::hashmap: Implement external iterator for HashMap and HashSet --- src/libstd/hashmap.rs | 90 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 11 deletions(-) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index d05fa63a6f9b3..c275e8a99ff58 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -20,12 +20,13 @@ use cmp::{Eq, Equiv}; use hash::Hash; use old_iter::BaseIter; use old_iter; -use iterator::{IteratorUtil}; +use iterator::{Iterator, IteratorUtil}; use option::{None, Option, Some}; use rand::RngUtil; use rand; use uint; use vec; +use vec::{ImmutableVector, MutableVector}; use kinds::Copy; use util::{replace, unreachable}; @@ -310,24 +311,17 @@ impl Map for HashMap { /// Visit all key-value pairs fn each<'a>(&'a self, blk: &fn(&K, &'a V) -> bool) -> bool { - for self.buckets.each |bucket| { - for bucket.iter().advance |pair| { - if !blk(&pair.key, &pair.value) { - return false; - } - } - } - return true; + self.iter().advance(|(k, v)| blk(k, v)) } /// Visit all keys fn each_key(&self, blk: &fn(k: &K) -> bool) -> bool { - self.each(|k, _| blk(k)) + self.iter().advance(|(k, _)| blk(k)) } /// Visit all values fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) -> bool { - self.each(|_, v| blk(v)) + self.iter().advance(|(_, v)| blk(v)) } /// Iterate over the map and mutate the contained values @@ -523,6 +517,19 @@ impl HashMap { TableFull | FoundHole(_) => None, } } + + /// An iterator visiting all key-value pairs in arbitrary order. + /// Iterator element type is (&'a K, &'a V). + pub fn iter<'a>(&'a self) -> HashMapIterator<'a, K, V> { + HashMapIterator { iter: self.buckets.iter() } + } + + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. + /// Iterator element type is (&'a K, &'a mut V). + pub fn mut_iter<'a>(&'a mut self) -> HashMapMutIterator<'a, K, V> { + HashMapMutIterator { iter: self.buckets.mut_iter() } + } } impl HashMap { @@ -554,6 +561,61 @@ impl Eq for HashMap { fn ne(&self, other: &HashMap) -> bool { !self.eq(other) } } +/// HashMap iterator +pub struct HashMapIterator<'self, K, V> { + priv iter: vec::VecIterator<'self, Option>>, +} + +/// HashMap mutable values iterator +pub struct HashMapMutIterator<'self, K, V> { + priv iter: vec::VecMutIterator<'self, Option>>, +} + +/// HashSet iterator +pub struct HashSetIterator<'self, K> { + priv iter: vec::VecIterator<'self, Option>>, +} + +impl<'self, K, V> Iterator<(&'self K, &'self V)> for HashMapIterator<'self, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'self K, &'self V)> { + for self.iter.advance |elt| { + match elt { + &Some(ref bucket) => return Some((&bucket.key, &bucket.value)), + &None => {}, + } + } + None + } +} + +impl<'self, K, V> Iterator<(&'self K, &'self mut V)> for HashMapMutIterator<'self, K, V> { + #[inline] + fn next(&mut self) -> Option<(&'self K, &'self mut V)> { + for self.iter.advance |elt| { + match elt { + &Some(ref mut bucket) => return Some((&bucket.key, &mut bucket.value)), + &None => {}, + } + } + None + } +} + +impl<'self, K> Iterator<&'self K> for HashSetIterator<'self, K> { + #[inline] + fn next(&mut self) -> Option<&'self K> { + for self.iter.advance |elt| { + match elt { + &Some(ref bucket) => return Some(&bucket.key), + &None => {}, + } + } + None + } +} + + /// An implementation of a hash set using the underlying representation of a /// HashMap where the value is (). As with the `HashMap` type, a `HashSet` /// requires that the elements implement the `Eq` and `Hash` traits. @@ -663,6 +725,12 @@ impl HashSet { pub fn contains_equiv>(&self, value: &Q) -> bool { self.map.contains_key_equiv(value) } + + /// An iterator visiting all elements in arbitrary order. + /// Iterator element type is &'a T. + pub fn iter<'a>(&'a self) -> HashSetIterator<'a, T> { + HashSetIterator { iter: self.map.buckets.iter() } + } } #[cfg(test)] From 7a17e22cde6bd34a9f52f105c9397ed8754d8f88 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:16 +0200 Subject: [PATCH 2/5] std::hashmap: Add test_iterate for HashSet --- src/libstd/hashmap.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index c275e8a99ff58..1c74901b94ded 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -952,6 +952,7 @@ mod test_set { use super::*; use container::{Container, Map, Set}; use vec; + use uint; #[test] fn test_disjoint() { @@ -1004,6 +1005,19 @@ mod test_set { assert!(b.is_superset(&a)); } + #[test] + fn test_iterate() { + let mut a = HashSet::new(); + for uint::range(0, 32) |i| { + assert!(a.insert(i)); + } + let mut observed = 0; + for a.iter().advance |k| { + observed |= (1 << *k); + } + assert_eq!(observed, 0xFFFF_FFFF); + } + #[test] fn test_intersection() { let mut a = HashSet::new(); From 9e5fe21fbaff32bc187eb210cdbaa7edad973851 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:26 +0200 Subject: [PATCH 3/5] std::hashmap: Use .iter() instead of .each and similar --- src/libstd/hashmap.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 1c74901b94ded..dddda60702aa5 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,6 @@ use container::{Container, Mutable, Map, Set}; use cmp::{Eq, Equiv}; use hash::Hash; use old_iter::BaseIter; -use old_iter; use iterator::{Iterator, IteratorUtil}; use option::{None, Option, Some}; use rand::RngUtil; @@ -548,7 +547,7 @@ impl Eq for HashMap { fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } - for self.each |key, value| { + for self.iter().advance |(key, value)| { match other.find(key) { None => return false, Some(v) => if value != v { return false }, @@ -662,12 +661,12 @@ impl Set for HashSet { /// Return true if the set has no elements in common with `other`. /// This is equivalent to checking for an empty intersection. fn is_disjoint(&self, other: &HashSet) -> bool { - old_iter::all(self, |v| !other.contains(v)) + self.iter().all(|v| !other.contains(v)) } /// Return true if the set is a subset of another fn is_subset(&self, other: &HashSet) -> bool { - old_iter::all(self, |v| other.contains(v)) + self.iter().all(|v| other.contains(v)) } /// Return true if the set is a superset of another @@ -677,7 +676,7 @@ impl Set for HashSet { /// Visit the values representing the difference fn difference(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { - self.each(|v| other.contains(v) || f(v)) + self.iter().advance(|v| other.contains(v) || f(v)) } /// Visit the values representing the symmetric difference @@ -689,12 +688,12 @@ impl Set for HashSet { /// Visit the values representing the intersection fn intersection(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { - self.each(|v| !other.contains(v) || f(v)) + self.iter().advance(|v| !other.contains(v) || f(v)) } /// Visit the values representing the union fn union(&self, other: &HashSet, f: &fn(&T) -> bool) -> bool { - self.each(f) && other.each(|v| self.contains(v) || f(v)) + self.iter().advance(f) && other.iter().advance(|v| self.contains(v) || f(v)) } } @@ -875,7 +874,7 @@ mod test_map { assert!(m.insert(i, i*2)); } let mut observed = 0; - for m.each |k, v| { + for m.iter().advance |(k, v)| { assert_eq!(*v, *k * 2); observed |= (1 << *k); } From 3a43c6a86e1107b78ee0cc4963bb00d09b9d24d5 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:29 +0200 Subject: [PATCH 4/5] std::hashmap: Remove BaseIter impl for HashSet Remove the BaseIter impl, while keeping the .each method until callers are converted. --- src/libstd/hashmap.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index dddda60702aa5..0b6bf339d7efd 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -18,7 +18,6 @@ use container::{Container, Mutable, Map, Set}; use cmp::{Eq, Equiv}; use hash::Hash; -use old_iter::BaseIter; use iterator::{Iterator, IteratorUtil}; use option::{None, Option, Some}; use rand::RngUtil; @@ -622,12 +621,6 @@ pub struct HashSet { priv map: HashMap } -impl BaseIter for HashSet { - /// Visit all values in order - fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) } - fn size_hint(&self) -> Option { Some(self.len()) } -} - impl Eq for HashSet { fn eq(&self, other: &HashSet) -> bool { self.map == other.map } fn ne(&self, other: &HashSet) -> bool { self.map != other.map } @@ -725,6 +718,12 @@ impl HashSet { self.map.contains_key_equiv(value) } + /// Visit all elements in arbitrary order + /// FIXME: Remove when all callers are converted + pub fn each(&self, f: &fn(&T) -> bool) -> bool { + self.iter().advance(f) + } + /// An iterator visiting all elements in arbitrary order. /// Iterator element type is &'a T. pub fn iter<'a>(&'a self) -> HashSetIterator<'a, T> { From 4550fb794d76b89d5322e2061337bbdc0ad76bb1 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:32 +0200 Subject: [PATCH 5/5] std::to_str: Use .iter() for HashMap and HashSet --- src/libstd/to_str.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libstd/to_str.rs b/src/libstd/to_str.rs index 3e782e728fe3c..ed69ed842bbb2 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -21,6 +21,7 @@ use container::Map; use hash::Hash; use cmp::Eq; use old_iter::BaseIter; +use iterator::IteratorUtil; /// A generic trait for converting a value to a string pub trait ToStr { @@ -54,7 +55,7 @@ impl ToStr for HashMap { #[inline] fn to_str(&self) -> ~str { let mut (acc, first) = (~"{", true); - for self.each |key, value| { + for self.iter().advance |(key, value)| { if first { first = false; } @@ -74,7 +75,7 @@ impl ToStr for HashSet { #[inline] fn to_str(&self) -> ~str { let mut (acc, first) = (~"{", true); - for self.each |element| { + for self.iter().advance |element| { if first { first = false; }