Skip to content

Commit e3b168d

Browse files
committed
vec: make the move iterator fast for all types
Closes #10976
1 parent dc7a2e1 commit e3b168d

File tree

2 files changed

+47
-50
lines changed

2 files changed

+47
-50
lines changed

src/libstd/hashmap.rs

+5-8
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
157157
vec::from_fn(new_capacity, |_| None));
158158

159159
self.size = 0;
160-
// move_rev_iter is more efficient
161-
for bucket in old_buckets.move_rev_iter() {
160+
for bucket in old_buckets.move_iter() {
162161
self.insert_opt_bucket(bucket);
163162
}
164163
}
@@ -477,8 +476,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
477476
/// pair out of the map in arbitrary order. The map cannot be used after
478477
/// calling this.
479478
pub fn move_iter(self) -> HashMapMoveIterator<K, V> {
480-
// `move_rev_iter` is more efficient than `move_iter` for vectors
481-
HashMapMoveIterator {iter: self.buckets.move_rev_iter()}
479+
HashMapMoveIterator {iter: self.buckets.move_iter()}
482480
}
483481
}
484482

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

533531
/// HashMap move iterator
534532
pub struct HashMapMoveIterator<K, V> {
535-
priv iter: vec::MoveRevIterator<Option<Bucket<K, V>>>,
533+
priv iter: vec::MoveIterator<Option<Bucket<K, V>>>,
536534
}
537535

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

544542
/// HashSet move iterator
545543
pub struct HashSetMoveIterator<K> {
546-
priv iter: vec::MoveRevIterator<Option<Bucket<K, ()>>>,
544+
priv iter: vec::MoveIterator<Option<Bucket<K, ()>>>,
547545
}
548546

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

736733
/// Visit the values representing the difference

src/libstd/vec.rs

+42-42
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,21 @@ There are a number of free functions that create or take vectors, for example:
102102
#[warn(non_camel_case_types)];
103103

104104
use cast;
105+
use ops::Drop;
105106
use clone::{Clone, DeepClone};
106107
use container::{Container, Mutable};
107108
use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
108109
use cmp;
109110
use default::Default;
110111
use iter::*;
111-
use libc::c_void;
112+
use libc::{c_char, c_void};
112113
use num::{Integer, CheckedAdd, Saturating};
113114
use option::{None, Option, Some};
114115
use ptr::to_unsafe_ptr;
115116
use ptr;
116117
use ptr::RawPtr;
117-
use rt::global_heap::malloc_raw;
118-
use rt::global_heap::realloc_raw;
118+
use rt::global_heap::{malloc_raw, realloc_raw, exchange_free};
119+
use rt::local_heap::local_free;
119120
use mem;
120121
use mem::size_of;
121122
use uint;
@@ -1325,9 +1326,6 @@ pub trait OwnedVector<T> {
13251326
/// value out of the vector (from start to end). The vector cannot
13261327
/// be used after calling this.
13271328
///
1328-
/// Note that this performs O(n) swaps, and so `move_rev_iter`
1329-
/// (which just calls `pop` repeatedly) is more efficient.
1330-
///
13311329
/// # Examples
13321330
///
13331331
/// ```rust
@@ -1339,8 +1337,7 @@ pub trait OwnedVector<T> {
13391337
/// ```
13401338
fn move_iter(self) -> MoveIterator<T>;
13411339
/// Creates a consuming iterator that moves out of the vector in
1342-
/// reverse order. Also see `move_iter`, however note that this
1343-
/// is more efficient.
1340+
/// reverse order.
13441341
fn move_rev_iter(self) -> MoveRevIterator<T>;
13451342

13461343
/**
@@ -1469,11 +1466,18 @@ pub trait OwnedVector<T> {
14691466
}
14701467

14711468
impl<T> OwnedVector<T> for ~[T] {
1469+
#[inline]
14721470
fn move_iter(self) -> MoveIterator<T> {
1473-
MoveIterator { v: self, idx: 0 }
1471+
unsafe {
1472+
let iter = cast::transmute(self.iter());
1473+
let ptr = cast::transmute(self);
1474+
MoveIterator { allocation: ptr, iter: iter }
1475+
}
14741476
}
1477+
1478+
#[inline]
14751479
fn move_rev_iter(self) -> MoveRevIterator<T> {
1476-
MoveRevIterator { v: self }
1480+
self.move_iter().invert()
14771481
}
14781482

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

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

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

26892680
#[inline]
26902681
fn size_hint(&self) -> (uint, Option<uint>) {
2691-
let l = self.v.len();
2692-
(l, Some(l))
2682+
self.iter.size_hint()
26932683
}
26942684
}
26952685

2696-
/// An iterator that moves out of a vector in reverse order.
2697-
#[deriving(Clone)]
2698-
pub struct MoveRevIterator<T> {
2699-
priv v: ~[T]
2700-
}
2701-
2702-
impl<T> Iterator<T> for MoveRevIterator<T> {
2686+
impl<T> DoubleEndedIterator<T> for MoveIterator<T> {
27032687
#[inline]
2704-
fn next(&mut self) -> Option<T> {
2705-
self.v.pop_opt()
2688+
fn next_back(&mut self) -> Option<T> {
2689+
unsafe {
2690+
self.iter.next_back().map(|x| ptr::read_ptr(x))
2691+
}
27062692
}
2693+
}
27072694

2708-
#[inline]
2709-
fn size_hint(&self) -> (uint, Option<uint>) {
2710-
let l = self.v.len();
2711-
(l, Some(l))
2695+
#[unsafe_destructor]
2696+
impl<T> Drop for MoveIterator<T> {
2697+
fn drop(&mut self) {
2698+
unsafe {
2699+
// destroy the remaining elements
2700+
for x in self.iter {
2701+
ptr::read_ptr(x);
2702+
}
2703+
if owns_managed::<T>() {
2704+
local_free(self.allocation as *u8 as *c_char)
2705+
} else {
2706+
exchange_free(self.allocation as *u8 as *c_char)
2707+
}
2708+
}
27122709
}
27132710
}
27142711

2712+
/// An iterator that moves out of a vector in reverse order.
2713+
pub type MoveRevIterator<T> = Invert<MoveIterator<T>>;
2714+
27152715
impl<A> FromIterator<A> for ~[A] {
27162716
fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
27172717
let (lower, _) = iterator.size_hint();

0 commit comments

Comments
 (0)