Skip to content

vec: make the move iterator fast for all types #10995

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

Merged
merged 1 commit into from
Dec 16, 2013
Merged
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
13 changes: 5 additions & 8 deletions src/libstd/hashmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
vec::from_fn(new_capacity, |_| None));

self.size = 0;
// move_rev_iter is more efficient
for bucket in old_buckets.move_rev_iter() {
for bucket in old_buckets.move_iter() {
self.insert_opt_bucket(bucket);
}
}
Expand Down Expand Up @@ -477,8 +476,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
/// pair out of the map in arbitrary order. The map cannot be used after
/// calling this.
pub fn move_iter(self) -> HashMapMoveIterator<K, V> {
// `move_rev_iter` is more efficient than `move_iter` for vectors
HashMapMoveIterator {iter: self.buckets.move_rev_iter()}
HashMapMoveIterator {iter: self.buckets.move_iter()}
}
}

Expand Down Expand Up @@ -532,7 +530,7 @@ pub struct HashMapMutIterator<'a, K, V> {

/// HashMap move iterator
pub struct HashMapMoveIterator<K, V> {
priv iter: vec::MoveRevIterator<Option<Bucket<K, V>>>,
priv iter: vec::MoveIterator<Option<Bucket<K, V>>>,
}

/// HashSet iterator
Expand All @@ -543,7 +541,7 @@ pub struct HashSetIterator<'a, K> {

/// HashSet move iterator
pub struct HashSetMoveIterator<K> {
priv iter: vec::MoveRevIterator<Option<Bucket<K, ()>>>,
priv iter: vec::MoveIterator<Option<Bucket<K, ()>>>,
}

impl<'a, K, V> Iterator<(&'a K, &'a V)> for HashMapIterator<'a, K, V> {
Expand Down Expand Up @@ -729,8 +727,7 @@ impl<T:Hash + Eq> HashSet<T> {
/// of the set in arbitrary order. The set cannot be used after calling
/// this.
pub fn move_iter(self) -> HashSetMoveIterator<T> {
// `move_rev_iter` is more efficient than `move_iter` for vectors
HashSetMoveIterator {iter: self.map.buckets.move_rev_iter()}
HashSetMoveIterator {iter: self.map.buckets.move_iter()}
}

/// Visit the values representing the difference
Expand Down
84 changes: 42 additions & 42 deletions src/libstd/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,20 +102,21 @@ There are a number of free functions that create or take vectors, for example:
#[warn(non_camel_case_types)];

use cast;
use ops::Drop;
use clone::{Clone, DeepClone};
use container::{Container, Mutable};
use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
use cmp;
use default::Default;
use iter::*;
use libc::c_void;
use libc::{c_char, c_void};
use num::{Integer, CheckedAdd, Saturating};
use option::{None, Option, Some};
use ptr::to_unsafe_ptr;
use ptr;
use ptr::RawPtr;
use rt::global_heap::malloc_raw;
use rt::global_heap::realloc_raw;
use rt::global_heap::{malloc_raw, realloc_raw, exchange_free};
use rt::local_heap::local_free;
use mem;
use mem::size_of;
use uint;
Expand Down Expand Up @@ -1325,9 +1326,6 @@ pub trait OwnedVector<T> {
/// value out of the vector (from start to end). The vector cannot
/// be used after calling this.
///
/// Note that this performs O(n) swaps, and so `move_rev_iter`
/// (which just calls `pop` repeatedly) is more efficient.
///
/// # Examples
///
/// ```rust
Expand All @@ -1339,8 +1337,7 @@ pub trait OwnedVector<T> {
/// ```
fn move_iter(self) -> MoveIterator<T>;
/// Creates a consuming iterator that moves out of the vector in
/// reverse order. Also see `move_iter`, however note that this
/// is more efficient.
/// reverse order.
fn move_rev_iter(self) -> MoveRevIterator<T>;

/**
Expand Down Expand Up @@ -1469,11 +1466,18 @@ pub trait OwnedVector<T> {
}

impl<T> OwnedVector<T> for ~[T] {
#[inline]
fn move_iter(self) -> MoveIterator<T> {
MoveIterator { v: self, idx: 0 }
unsafe {
let iter = cast::transmute(self.iter());
let ptr = cast::transmute(self);
MoveIterator { allocation: ptr, iter: iter }
}
}

#[inline]
fn move_rev_iter(self) -> MoveRevIterator<T> {
MoveRevIterator { v: self }
self.move_iter().invert()
}

fn reserve(&mut self, n: uint) {
Expand Down Expand Up @@ -2660,58 +2664,54 @@ impl<'a, T> DoubleEndedIterator<&'a mut [T]> for MutChunkIter<'a, T> {
}

/// An iterator that moves out of a vector.
#[deriving(Clone)]
pub struct MoveIterator<T> {
priv v: ~[T],
priv idx: uint,
priv allocation: *mut u8, // the block of memory allocated for the vector
priv iter: VecIterator<'static, T>
}

impl<T> Iterator<T> for MoveIterator<T> {
#[inline]
fn next(&mut self) -> Option<T> {
// this is peculiar, but is required for safety with respect
// to dtors. It traverses the first half of the vec, and
// removes them by swapping them with the last element (and
// popping), which results in the second half in reverse
// order, and so these can just be pop'd off. That is,
//
// [1,2,3,4,5] => 1, [5,2,3,4] => 2, [5,4,3] => 3, [5,4] => 4,
// [5] -> 5, []
let l = self.v.len();
if self.idx < l {
self.v.swap(self.idx, l - 1);
self.idx += 1;
unsafe {
self.iter.next().map(|x| ptr::read_ptr(x))
}

self.v.pop_opt()
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let l = self.v.len();
(l, Some(l))
self.iter.size_hint()
}
}

/// An iterator that moves out of a vector in reverse order.
#[deriving(Clone)]
pub struct MoveRevIterator<T> {
priv v: ~[T]
}

impl<T> Iterator<T> for MoveRevIterator<T> {
impl<T> DoubleEndedIterator<T> for MoveIterator<T> {
#[inline]
fn next(&mut self) -> Option<T> {
self.v.pop_opt()
fn next_back(&mut self) -> Option<T> {
unsafe {
self.iter.next_back().map(|x| ptr::read_ptr(x))
}
}
}

#[inline]
fn size_hint(&self) -> (uint, Option<uint>) {
let l = self.v.len();
(l, Some(l))
#[unsafe_destructor]
impl<T> Drop for MoveIterator<T> {
fn drop(&mut self) {
unsafe {
// destroy the remaining elements
for x in self.iter {
ptr::read_ptr(x);
}
if owns_managed::<T>() {
local_free(self.allocation as *u8 as *c_char)
} else {
exchange_free(self.allocation as *u8 as *c_char)
}
}
}
}

/// An iterator that moves out of a vector in reverse order.
pub type MoveRevIterator<T> = Invert<MoveIterator<T>>;

impl<A> FromIterator<A> for ~[A] {
fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
let (lower, _) = iterator.size_hint();
Expand Down