Skip to content

Commit

Permalink
Use wrapper structs for HashMap's iterators.
Browse files Browse the repository at this point in the history
Using a type alias for iterator implementations is fragile since this
exposes the implementation to users of the iterator, and any changes
could break existing code.

This commit changes the keys and values iterators of `HashMap` to use
proper new types, rather than type aliases.  However, since it is
fair-game to treat a type-alias as the aliased type, this is a:

[breaking-change].
  • Loading branch information
csouth3 committed Dec 16, 2014
1 parent a81c3ab commit 85fe141
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 38 deletions.
64 changes: 29 additions & 35 deletions src/libstd/collections/hash/map.rs
Expand Up @@ -20,7 +20,7 @@ use cmp::{max, Eq, Equiv, PartialEq};
use default::Default;
use fmt::{mod, Show};
use hash::{Hash, Hasher, RandomSipHasher};
use iter::{mod, Iterator, IteratorExt, FromIterator, Extend};
use iter::{mod, Iterator, IteratorExt, FromIterator, Extend, Map};
use kinds::Sized;
use mem::{mod, replace};
use num::{Int, UnsignedInt};
Expand Down Expand Up @@ -859,7 +859,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
pub fn keys(&self) -> Keys<K, V> {
fn first<A, B>((a, _): (A, B)) -> A { a }

self.iter().map(first)
Keys { inner: self.iter().map(first) }
}

/// An iterator visiting all values in arbitrary order.
Expand All @@ -883,7 +883,7 @@ impl<K: Eq + Hash<S>, V, S, H: Hasher<S>> HashMap<K, V, H> {
pub fn values(&self) -> Values<K, V> {
fn second<A, B>((_, b): (A, B)) -> B { b }

self.iter().map(second)
Values { inner: self.iter().map(second) }
}

/// An iterator visiting all key-value pairs in arbitrary order.
Expand Down Expand Up @@ -1335,6 +1335,16 @@ pub struct MoveEntries<K, V> {
>
}

/// HashMap keys iterator
pub struct Keys<'a, K: 'a, V: 'a> {
inner: Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>
}

/// HashMap values iterator
pub struct Values<'a, K: 'a, V: 'a> {
inner: Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>
}

/// A view into a single occupied location in a HashMap
pub struct OccupiedEntry<'a, K:'a, V:'a> {
elem: FullBucket<K, V, &'a mut RawTable<K, V>>,
Expand Down Expand Up @@ -1365,36 +1375,28 @@ enum VacantEntryState<K, V, M> {
}

impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a V)> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
self.inner.size_hint()
}
#[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() }
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}

impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> {
#[inline]
fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
self.inner.size_hint()
}
#[inline] fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.inner.next() }
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}

impl<K, V> Iterator<(K, V)> for MoveEntries<K, V> {
#[inline]
fn next(&mut self) -> Option<(K, V)> {
self.inner.next()
}
#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
self.inner.size_hint()
}
#[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() }
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}

impl<'a, K, V> Iterator<&'a K> for Keys<'a, K, V> {
#[inline] fn next(&mut self) -> Option<(&'a K)> { self.inner.next() }
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}

impl<'a, K, V> Iterator<&'a V> for Values<'a, K, V> {
#[inline] fn next(&mut self) -> Option<(&'a V)> { self.inner.next() }
#[inline] fn size_hint(&self) -> (uint, Option<uint>) { self.inner.size_hint() }
}

impl<'a, K, V> OccupiedEntry<'a, K, V> {
Expand Down Expand Up @@ -1448,14 +1450,6 @@ impl<'a, K, V> VacantEntry<'a, K, V> {
}
}

/// HashMap keys iterator
pub type Keys<'a, K, V> =
iter::Map<(&'a K, &'a V), &'a K, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a K>;

/// HashMap values iterator
pub type Values<'a, K, V> =
iter::Map<(&'a K, &'a V), &'a V, Entries<'a, K, V>, fn((&'a K, &'a V)) -> &'a V>;

impl<K: Eq + Hash<S>, V, S, H: Hasher<S> + Default> FromIterator<(K, V)> for HashMap<K, V, H> {
fn from_iter<T: Iterator<(K, V)>>(iter: T) -> HashMap<K, V, H> {
let (lower, _) = iter.size_hint();
Expand Down
5 changes: 2 additions & 3 deletions src/libstd/collections/hash/set.rs
Expand Up @@ -22,7 +22,7 @@ use iter;
use option::Option::{Some, None, mod};
use result::Result::{Ok, Err};

use super::map::{HashMap, Entries, MoveEntries, INITIAL_CAPACITY};
use super::map::{HashMap, MoveEntries, Keys, INITIAL_CAPACITY};

// FIXME(conventions): implement BitOr, BitAnd, BitXor, and Sub

Expand Down Expand Up @@ -617,8 +617,7 @@ impl<T: Eq + Hash<S>, S, H: Hasher<S> + Default> Default for HashSet<T, H> {
}

/// HashSet iterator
pub type SetItems<'a, K> =
iter::Map<(&'a K, &'a ()), &'a K, Entries<'a, K, ()>, fn((&'a K, &'a ())) -> &'a K>;
pub type SetItems<'a, K> = Keys<'a, K, ()>;

/// HashSet move iterator
pub type SetMoveItems<K> = iter::Map<(K, ()), K, MoveEntries<K, ()>, fn((K, ())) -> K>;
Expand Down

0 comments on commit 85fe141

Please sign in to comment.