From 080d498af224ac4b60efe6e92aed08db3f247bc5 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:05 +0200 Subject: [PATCH 1/6] std::hashmap: Implement external iterator for HashMap and HashSet --- src/libstd/hashmap.rs | 91 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 79 insertions(+), 12 deletions(-) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 02fa2de4b032c..c275e8a99ff58 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -20,13 +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; +use vec::{ImmutableVector, MutableVector}; use kinds::Copy; use util::{replace, unreachable}; @@ -311,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.iter().advance |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 @@ -524,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 { @@ -555,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. @@ -664,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 3af1d20bea80faaf5fe14a56c94e8e7337691e0d Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:16 +0200 Subject: [PATCH 2/6] 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 f045210857a8936c7d6ce36a3029eac906dedc4e Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:26 +0200 Subject: [PATCH 3/6] 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 13f666a72468ad20d5145ff5d618ef31c479c1a2 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:29 +0200 Subject: [PATCH 4/6] 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 8baefec013876a46c084cf88d48c760a659e713f Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Fri, 21 Jun 2013 17:05:32 +0200 Subject: [PATCH 5/6] 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 c6ac2c89f32ee..56078a69f28f3 100644 --- a/src/libstd/to_str.rs +++ b/src/libstd/to_str.rs @@ -23,6 +23,7 @@ use hash::Hash; use cmp::Eq; use old_iter::BaseIter; use vec::ImmutableVector; +use iterator::IteratorUtil; /// A generic trait for converting a value to a string pub trait ToStr { @@ -56,7 +57,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; } @@ -76,7 +77,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; } From ac2e167e7ed73cdb8863075d09633bb91ca0028f Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sun, 23 Jun 2013 05:13:13 -0400 Subject: [PATCH 6/6] hashmap: add FIXME number --- src/libstd/hashmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 0b6bf339d7efd..7d55947e81881 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -719,7 +719,7 @@ impl HashSet { } /// Visit all elements in arbitrary order - /// FIXME: Remove when all callers are converted + /// FIXME: #6978: Remove when all callers are converted pub fn each(&self, f: &fn(&T) -> bool) -> bool { self.iter().advance(f) }