From 67ae3a49e4864133784cd745a9a8866889f3ae15 Mon Sep 17 00:00:00 2001 From: Tobias Bucher <tobiasbucher5991@gmail.com> Date: Tue, 9 Dec 2014 18:17:18 +0100 Subject: [PATCH 1/2] Clean up `libcollections::VecMap` - Introduce a named type for the return type of `VecMap::move_iter` - Rename all type parameters to `V` for "Value". - Remove unnecessary call to an `Option::unwrap`, use pattern matching instead. - Remove incorrect `Hash` implementation which took the `VecMap`'s capacity into account. This is a [breaking-change], however whoever used the `Hash` implementation relied on an incorrect implementation. --- src/libcollections/vec_map.rs | 89 ++++++++++++++--------------------- 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index 36e66ed27f3..cbe48bf45e7 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -23,8 +23,6 @@ use core::mem::replace; use {vec, slice}; use vec::Vec; -use hash; -use hash::Hash; // FIXME(conventions): capacity management??? @@ -62,8 +60,8 @@ use hash::Hash; /// assert!(months.is_empty()); /// ``` #[deriving(PartialEq, Eq)] -pub struct VecMap<T> { - v: Vec<Option<T>>, +pub struct VecMap<V> { + v: Vec<Option<V>>, } impl<V> Default for VecMap<V> { @@ -83,12 +81,6 @@ impl<V:Clone> Clone for VecMap<V> { } } -impl <S: hash::Writer, T: Hash<S>> Hash<S> for VecMap<T> { - fn hash(&self, state: &mut S) { - self.v.hash(state) - } -} - impl<V> VecMap<V> { /// Creates an empty `VecMap`. /// @@ -99,7 +91,7 @@ impl<V> VecMap<V> { /// let mut map: VecMap<&str> = VecMap::new(); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn new() -> VecMap<V> { VecMap{v: vec!()} } + pub fn new() -> VecMap<V> { VecMap { v: vec![] } } /// Creates an empty `VecMap` with space for at least `capacity` /// elements before resizing. @@ -207,10 +199,7 @@ impl<V> VecMap<V> { /// assert_eq!(vec, vec![(1, "a"), (2, "b"), (3, "c")]); /// ``` #[unstable = "matches collection reform specification, waiting for dust to settle"] - pub fn into_iter(&mut self) - -> FilterMap<(uint, Option<V>), (uint, V), - Enumerate<vec::MoveItems<Option<V>>>> - { + pub fn into_iter(&mut self) -> MoveItems<V> { let values = replace(&mut self.v, vec!()); values.into_iter().enumerate().filter_map(|(i, v)| { v.map(|v| (i, v)) @@ -523,16 +512,19 @@ impl<V> IndexMut<uint, V> for VecMap<V> { macro_rules! iterator { (impl $name:ident -> $elem:ty, $($getter:ident),+) => { - impl<'a, T> Iterator<$elem> for $name<'a, T> { + impl<'a, V> Iterator<$elem> for $name<'a, V> { #[inline] fn next(&mut self) -> Option<$elem> { while self.front < self.back { match self.iter.next() { Some(elem) => { - if elem.is_some() { - let index = self.front; - self.front += 1; - return Some((index, elem $(. $getter ())+)); + match elem$(. $getter ())+ { + Some(x) => { + let index = self.front; + self.front += 1; + return Some((index, x)); + }, + None => {}, } } _ => () @@ -552,15 +544,18 @@ macro_rules! iterator { macro_rules! double_ended_iterator { (impl $name:ident -> $elem:ty, $($getter:ident),+) => { - impl<'a, T> DoubleEndedIterator<$elem> for $name<'a, T> { + impl<'a, V> DoubleEndedIterator<$elem> for $name<'a, V> { #[inline] fn next_back(&mut self) -> Option<$elem> { while self.front < self.back { match self.iter.next_back() { Some(elem) => { - if elem.is_some() { - self.back -= 1; - return Some((self.back, elem$(. $getter ())+)); + match elem$(. $getter ())+ { + Some(x) => { + self.back -= 1; + return Some((self.back, x)); + }, + None => {}, } } _ => () @@ -574,39 +569,42 @@ macro_rules! double_ended_iterator { } /// Forward iterator over a map. -pub struct Entries<'a, T:'a> { +pub struct Entries<'a, V:'a> { front: uint, back: uint, - iter: slice::Items<'a, Option<T>> + iter: slice::Items<'a, Option<V>> } -iterator!(impl Entries -> (uint, &'a T), as_ref, unwrap) -double_ended_iterator!(impl Entries -> (uint, &'a T), as_ref, unwrap) +iterator!(impl Entries -> (uint, &'a V), as_ref) +double_ended_iterator!(impl Entries -> (uint, &'a V), as_ref) /// Forward iterator over the key-value pairs of a map, with the /// values being mutable. -pub struct MutEntries<'a, T:'a> { +pub struct MutEntries<'a, V:'a> { front: uint, back: uint, - iter: slice::MutItems<'a, Option<T>> + iter: slice::MutItems<'a, Option<V>> } -iterator!(impl MutEntries -> (uint, &'a mut T), as_mut, unwrap) -double_ended_iterator!(impl MutEntries -> (uint, &'a mut T), as_mut, unwrap) +iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) +double_ended_iterator!(impl MutEntries -> (uint, &'a mut V), as_mut) /// Forward iterator over the keys of a map -pub type Keys<'a, T> = - iter::Map<'static, (uint, &'a T), uint, Entries<'a, T>>; +pub type Keys<'a, V> = + iter::Map<'static, (uint, &'a V), uint, Entries<'a, V>>; /// Forward iterator over the values of a map -pub type Values<'a, T> = - iter::Map<'static, (uint, &'a T), &'a T, Entries<'a, T>>; +pub type Values<'a, V> = + iter::Map<'static, (uint, &'a V), &'a V, Entries<'a, V>>; + +/// Iterator over the key-value pairs of a map, the iterator consumes the map +pub type MoveItems<V> = + FilterMap<'static, (uint, Option<V>), (uint, V), Enumerate<vec::MoveItems<Option<V>>>>; #[cfg(test)] mod test_map { use std::prelude::*; use vec::Vec; - use hash; use super::VecMap; @@ -920,23 +918,6 @@ mod test_map { assert!(a < b && a <= b); } - #[test] - fn test_hash() { - let mut x = VecMap::new(); - let mut y = VecMap::new(); - - assert!(hash::hash(&x) == hash::hash(&y)); - x.insert(1, 'a'); - x.insert(2, 'b'); - x.insert(3, 'c'); - - y.insert(3, 'c'); - y.insert(2, 'b'); - y.insert(1, 'a'); - - assert!(hash::hash(&x) == hash::hash(&y)); - } - #[test] fn test_from_iter() { let xs: Vec<(uint, char)> = vec![(1u, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')]; From 20eaf168c5b40c003bd7d28fe4c071b24118410e Mon Sep 17 00:00:00 2001 From: Tobias Bucher <tobiasbucher5991@gmail.com> Date: Tue, 9 Dec 2014 20:05:51 +0100 Subject: [PATCH 2/2] Add a proper `Hash` implementation for `VecMap` Also re-add the previously deleted test with an additional test that would have failed before, when the hash function depended on the capacity. --- src/libcollections/vec_map.rs | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs index cbe48bf45e7..e2efcb62ba9 100644 --- a/src/libcollections/vec_map.rs +++ b/src/libcollections/vec_map.rs @@ -21,6 +21,7 @@ use core::iter; use core::iter::{Enumerate, FilterMap}; use core::mem::replace; +use hash::{Hash, Writer}; use {vec, slice}; use vec::Vec; @@ -81,6 +82,19 @@ impl<V:Clone> Clone for VecMap<V> { } } +impl<S: Writer, V: Hash<S>> Hash<S> for VecMap<V> { + fn hash(&self, state: &mut S) { + // In order to not traverse the `VecMap` twice, count the elements + // during iteration. + let mut count: uint = 0; + for elt in self.iter() { + elt.hash(state); + count += 1; + } + count.hash(state); + } +} + impl<V> VecMap<V> { /// Creates an empty `VecMap`. /// @@ -605,6 +619,7 @@ pub type MoveItems<V> = mod test_map { use std::prelude::*; use vec::Vec; + use hash::hash; use super::VecMap; @@ -918,6 +933,28 @@ mod test_map { assert!(a < b && a <= b); } + #[test] + fn test_hash() { + let mut x = VecMap::new(); + let mut y = VecMap::new(); + + assert!(hash(&x) == hash(&y)); + x.insert(1, 'a'); + x.insert(2, 'b'); + x.insert(3, 'c'); + + y.insert(3, 'c'); + y.insert(2, 'b'); + y.insert(1, 'a'); + + assert!(hash(&x) == hash(&y)); + + x.insert(1000, 'd'); + x.remove(&1000); + + assert!(hash(&x) == hash(&y)); + } + #[test] fn test_from_iter() { let xs: Vec<(uint, char)> = vec![(1u, 'a'), (2, 'b'), (3, 'c'), (4, 'd'), (5, 'e')];