diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 662ae913764f4..cc7bb8600b98d 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, FromIterator, Extend}; +use iter::{mod, Iterator, DoubleEndedIterator, ExactSize, FromIterator, Extend}; use kinds::Sized; use mem::{mod, replace}; use num::UnsignedInt; @@ -1325,6 +1325,15 @@ impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<(&'a K, &'a V)> for Entries<'a, K, V> { + #[inline] + fn next_back(&mut self) -> Option<(&'a K, &'a V)> { + self.inner.next_back() + } +} + +impl<'a, K, V> ExactSize<(&'a K, &'a V)> for Entries<'a, K, V> {} + 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)> { @@ -1336,6 +1345,15 @@ impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { + #[inline] + fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { + self.inner.next_back() + } +} + +impl<'a, K, V> ExactSize<(&'a K, &'a mut V)> for MutEntries<'a, K, V> {} + impl Iterator<(K, V)> for MoveEntries { #[inline] fn next(&mut self) -> Option<(K, V)> { @@ -1347,6 +1365,15 @@ impl Iterator<(K, V)> for MoveEntries { } } +impl DoubleEndedIterator<(K, V)> for MoveEntries { + #[inline] + fn next_back(&mut self) -> Option<(K, V)> { + self.inner.next_back() + } +} + +impl ExactSize<(K, V)> for MoveEntries {} + impl<'a, K, V> OccupiedEntry<'a, K, V> { /// Gets a reference to the value in the entry pub fn get(&self) -> &V { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index f41ccea0aaf03..919d5b63245e2 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -15,7 +15,7 @@ pub use self::BucketState::*; use clone::Clone; use cmp; use hash::{Hash, Hasher}; -use iter::{Iterator, count}; +use iter::{Iterator, DoubleEndedIterator, ExactSize, count}; use kinds::{Sized, marker}; use mem::{min_align_of, size_of}; use mem; @@ -620,6 +620,25 @@ impl RawTable { } } + fn one_past_last_bucket_raw(&self) -> RawBucket { + let hashes_size = self.capacity * size_of::(); + let keys_size = self.capacity * size_of::(); + let vals_size = self.capacity * size_of::(); + + let buffer = self.hashes as *mut u8; + let (keys_offset, vals_offset) = calculate_offsets(hashes_size, + keys_size, min_align_of::(), + min_align_of::()); + + unsafe { + RawBucket { + hash: self.hashes.offset(hashes_size as int), + key: buffer.offset(keys_offset as int + keys_size as int) as *mut K, + val: buffer.offset(vals_offset as int + vals_size as int) as *mut V + } + } + } + /// Creates a new raw table from a given capacity. All buckets are /// initially empty. #[allow(experimental)] @@ -644,10 +663,8 @@ impl RawTable { fn raw_buckets(&self) -> RawBuckets { RawBuckets { - raw: self.first_bucket_raw(), - hashes_end: unsafe { - self.hashes.offset(self.capacity as int) - }, + start: self.first_bucket_raw(), + end: self.one_past_last_bucket_raw(), marker: marker::ContravariantLifetime, } } @@ -667,12 +684,12 @@ impl RawTable { } pub fn into_iter(self) -> MoveEntries { - let RawBuckets { raw, hashes_end, .. } = self.raw_buckets(); + let RawBuckets { start, end, .. } = self.raw_buckets(); // Replace the marker regardless of lifetime bounds on parameters. MoveEntries { iter: RawBuckets { - raw: raw, - hashes_end: hashes_end, + start: start, + end: end, marker: marker::ContravariantLifetime, }, table: self, @@ -695,18 +712,18 @@ impl RawTable { /// A raw iterator. The basis for some other iterators in this module. Although /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { - raw: RawBucket, - hashes_end: *mut u64, + start: RawBucket, + end: RawBucket, // points one after the end. marker: marker::ContravariantLifetime<'a>, } impl<'a, K, V> Iterator> for RawBuckets<'a, K, V> { fn next(&mut self) -> Option> { - while self.raw.hash != self.hashes_end { + while self.start.hash != self.end.hash { unsafe { // We are swapping out the pointer to a bucket and replacing // it with the pointer to the next one. - let prev = ptr::replace(&mut self.raw, self.raw.offset(1)); + let prev = ptr::replace(&mut self.start, self.start.offset(1)); if *prev.hash != EMPTY_BUCKET { return Some(prev); } @@ -717,6 +734,21 @@ impl<'a, K, V> Iterator> for RawBuckets<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator> for RawBuckets<'a, K, V> { + fn next_back(&mut self) -> Option> { + while self.start.hash != self.end.hash { + unsafe { + let next = ptr::replace(&mut self.end, self.end.offset(-1)); + if *next.hash != EMPTY_BUCKET { + return Some(next); + } + } + } + + None + } +} + /// An iterator that moves out buckets in reverse order. It leaves the table /// in an inconsistent state and should only be used for dropping /// the table's remaining entries. It's used in the implementation of Drop. @@ -785,6 +817,20 @@ impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<(&'a K, &'a V)> for Entries<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a V)> { + self.iter.next_back().map(|bucket| { + self.elems_left += 1; + unsafe { + (&*bucket.key, + &*bucket.val) + } + }) + } +} + +impl<'a, K, V> ExactSize<(&'a K, &'a V)> for Entries<'a, K, V> {} + impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { fn next(&mut self) -> Option<(&'a K, &'a mut V)> { self.iter.next().map(|bucket| { @@ -801,6 +847,20 @@ impl<'a, K, V> Iterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { } } +impl<'a, K, V> DoubleEndedIterator<(&'a K, &'a mut V)> for MutEntries<'a, K, V> { + fn next_back(&mut self) -> Option<(&'a K, &'a mut V)> { + self.iter.next().map(|bucket| { + self.elems_left += 1; + unsafe { + (&*bucket.key, + &mut *bucket.val) + } + }) + } +} + +impl<'a, K, V> ExactSize<(&'a K, &'a mut V)> for MutEntries<'a, K, V> {} + impl Iterator<(SafeHash, K, V)> for MoveEntries { fn next(&mut self) -> Option<(SafeHash, K, V)> { self.iter.next().map(|bucket| { @@ -823,6 +883,25 @@ impl Iterator<(SafeHash, K, V)> for MoveEntries { } } +impl DoubleEndedIterator<(SafeHash, K, V)> for MoveEntries { + fn next_back(&mut self) -> Option<(SafeHash, K, V)> { + self.iter.next().map(|bucket| { + self.table.size += 1; + unsafe { + ( + SafeHash { + hash: *bucket.hash, + }, + ptr::read(bucket.key as *const K), + ptr::read(bucket.val as *const V) + ) + } + }) + } +} + +impl ExactSize<(SafeHash, K, V)> for MoveEntries {} + impl Clone for RawTable { fn clone(&self) -> RawTable { unsafe {