From 85fe141fb7c066e88a6872e74347c5f34d0223a7 Mon Sep 17 00:00:00 2001 From: Chase Southwood Date: Fri, 12 Dec 2014 01:02:19 -0600 Subject: [PATCH] Use wrapper structs for `HashMap`'s iterators. 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]. --- src/libstd/collections/hash/map.rs | 64 ++++++++++++++---------------- src/libstd/collections/hash/set.rs | 5 +-- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2a8d97eed05bc..d22e7b2f764f5 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -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}; @@ -859,7 +859,7 @@ impl, V, S, H: Hasher> HashMap { pub fn keys(&self) -> Keys { fn first((a, _): (A, B)) -> A { a } - self.iter().map(first) + Keys { inner: self.iter().map(first) } } /// An iterator visiting all values in arbitrary order. @@ -883,7 +883,7 @@ impl, V, S, H: Hasher> HashMap { pub fn values(&self) -> Values { fn second((_, 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. @@ -1335,6 +1335,16 @@ pub struct MoveEntries { > } +/// 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>, @@ -1365,36 +1375,28 @@ enum VacantEntryState { } 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) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(&'a K, &'a V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option) { 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) { - 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) { self.inner.size_hint() } } impl Iterator<(K, V)> for MoveEntries { - #[inline] - fn next(&mut self) -> Option<(K, V)> { - self.inner.next() - } - #[inline] - fn size_hint(&self) -> (uint, Option) { - self.inner.size_hint() - } + #[inline] fn next(&mut self) -> Option<(K, V)> { self.inner.next() } + #[inline] fn size_hint(&self) -> (uint, Option) { 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) { 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) { self.inner.size_hint() } } impl<'a, K, V> OccupiedEntry<'a, K, V> { @@ -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, V, S, H: Hasher + Default> FromIterator<(K, V)> for HashMap { fn from_iter>(iter: T) -> HashMap { let (lower, _) = iter.size_hint(); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 745a8298ee8a5..3993a23140b45 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -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 @@ -617,8 +617,7 @@ impl, S, H: Hasher + Default> Default for HashSet { } /// 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 = iter::Map<(K, ()), K, MoveEntries, fn((K, ())) -> K>;