Skip to content

External Iterators for HashMap and HashSet #7277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 106 additions & 26 deletions src/libstd/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,13 @@
use container::{Container, Mutable, Map, Set};
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};

Expand Down Expand Up @@ -310,24 +309,17 @@ impl<K:Hash + Eq,V> Map<K, V> for HashMap<K, V> {

/// 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
Expand Down Expand Up @@ -523,6 +515,19 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
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<K: Hash + Eq, V: Copy> HashMap<K, V> {
Expand All @@ -541,7 +546,7 @@ impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> {
fn eq(&self, other: &HashMap<K, V>) -> 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 },
Expand All @@ -554,19 +559,68 @@ impl<K:Hash + Eq,V:Eq> Eq for HashMap<K, V> {
fn ne(&self, other: &HashMap<K, V>) -> bool { !self.eq(other) }
}

/// HashMap iterator
pub struct HashMapIterator<'self, K, V> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, V>>>,
}

/// HashMap mutable values iterator
pub struct HashMapMutIterator<'self, K, V> {
priv iter: vec::VecMutIterator<'self, Option<Bucket<K, V>>>,
}

/// HashSet iterator
pub struct HashSetIterator<'self, K> {
priv iter: vec::VecIterator<'self, Option<Bucket<K, ()>>>,
}

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.
pub struct HashSet<T> {
priv map: HashMap<T, ()>
}

impl<T:Hash + Eq> BaseIter<T> for HashSet<T> {
/// Visit all values in order
fn each(&self, f: &fn(&T) -> bool) -> bool { self.map.each_key(f) }
fn size_hint(&self) -> Option<uint> { Some(self.len()) }
}

impl<T:Hash + Eq> Eq for HashSet<T> {
fn eq(&self, other: &HashSet<T>) -> bool { self.map == other.map }
fn ne(&self, other: &HashSet<T>) -> bool { self.map != other.map }
Expand Down Expand Up @@ -600,12 +654,12 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> {
/// 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<T>) -> 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<T>) -> 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
Expand All @@ -615,7 +669,7 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> {

/// Visit the values representing the difference
fn difference(&self, other: &HashSet<T>, 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
Expand All @@ -627,12 +681,12 @@ impl<T:Hash + Eq> Set<T> for HashSet<T> {

/// Visit the values representing the intersection
fn intersection(&self, other: &HashSet<T>, 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<T>, 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))
}
}

Expand Down Expand Up @@ -663,6 +717,18 @@ impl<T:Hash + Eq> HashSet<T> {
pub fn contains_equiv<Q:Hash + Equiv<T>>(&self, value: &Q) -> bool {
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> {
HashSetIterator { iter: self.map.buckets.iter() }
}
}

#[cfg(test)]
Expand Down Expand Up @@ -807,7 +873,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);
}
Expand Down Expand Up @@ -884,6 +950,7 @@ mod test_set {
use super::*;
use container::{Container, Map, Set};
use vec;
use uint;

#[test]
fn test_disjoint() {
Expand Down Expand Up @@ -936,6 +1003,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();
Expand Down
5 changes: 3 additions & 2 deletions src/libstd/to_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -54,7 +55,7 @@ impl<A:ToStr+Hash+Eq, B:ToStr+Hash+Eq> ToStr for HashMap<A, B> {
#[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;
}
Expand All @@ -74,7 +75,7 @@ impl<A:ToStr+Hash+Eq> ToStr for HashSet<A> {
#[inline]
fn to_str(&self) -> ~str {
let mut (acc, first) = (~"{", true);
for self.each |element| {
for self.iter().advance |element| {
if first {
first = false;
}
Expand Down