deque: Speed up deque growth by a lot
Fix some issues with the deque being very slow, keep the same vec around instead of constructing a new. Move as few elements as possible, so the self.lo point is not moved after grow. [o o o o o|o o o] hi...^ ^.... lo grows to [. . . . .|o o o o o o o o|. . .] ^.. lo ^.. hi If the deque is append-only, it will result in moving no elements on grow. If the deque is prepend-only, all will be moved each time. The bench tests added show big improvements: Timed using `rust build -O --test extra.rs && ./extra --bench deque` Old version: test deque::tests::bench_add_back ... bench: 4976 ns/iter (+/- 9) test deque::tests::bench_add_front ... bench: 4108 ns/iter (+/- 18) test deque::tests::bench_grow ... bench: 416964 ns/iter (+/- 4197) test deque::tests::bench_new ... bench: 408 ns/iter (+/- 12) With this commit: test deque::tests::bench_add_back ... bench: 12 ns/iter (+/- 0) test deque::tests::bench_add_front ... bench: 16 ns/iter (+/- 0) test deque::tests::bench_grow ... bench: 1515 ns/iter (+/- 30) test deque::tests::bench_new ... bench: 419 ns/iter (+/- 3)
This commit is contained in:
parent
81933edf92
commit
40ce0b7d76
@ -11,7 +11,6 @@
|
||||
//! A double-ended queue implemented as a circular buffer
|
||||
|
||||
use std::uint;
|
||||
use std::util::replace;
|
||||
use std::vec;
|
||||
use std::cast::transmute;
|
||||
|
||||
@ -103,15 +102,13 @@ impl<T> Deque<T> {
|
||||
|
||||
/// Prepend an element to the deque
|
||||
pub fn add_front(&mut self, t: T) {
|
||||
let oldlo = self.lo;
|
||||
if self.nelts == self.elts.len() {
|
||||
grow(self.nelts, self.lo, &mut self.elts);
|
||||
self.hi = self.lo + self.nelts;
|
||||
}
|
||||
if self.lo == 0u {
|
||||
self.lo = self.elts.len() - 1u;
|
||||
} else { self.lo -= 1u; }
|
||||
if self.nelts == self.elts.len() {
|
||||
self.elts = grow(self.nelts, oldlo, self.elts);
|
||||
self.lo = self.elts.len() - 1u;
|
||||
self.hi = self.nelts;
|
||||
}
|
||||
self.elts[self.lo] = Some(t);
|
||||
self.nelts += 1u;
|
||||
}
|
||||
@ -119,12 +116,14 @@ impl<T> Deque<T> {
|
||||
/// Append an element to the deque
|
||||
pub fn add_back(&mut self, t: T) {
|
||||
if self.lo == self.hi && self.nelts != 0u {
|
||||
self.elts = grow(self.nelts, self.lo, self.elts);
|
||||
self.lo = 0u;
|
||||
self.hi = self.nelts;
|
||||
grow(self.nelts, self.lo, &mut self.elts);
|
||||
self.hi = self.lo + self.nelts;
|
||||
}
|
||||
self.elts[self.hi] = Some(t);
|
||||
self.hi = (self.hi + 1u) % self.elts.len();
|
||||
self.hi += 1;
|
||||
if self.hi == self.elts.len() {
|
||||
self.hi = 0;
|
||||
}
|
||||
self.nelts += 1u;
|
||||
}
|
||||
|
||||
@ -235,15 +234,19 @@ iterator!{impl DequeMutRevIterator -> &'self mut T, -1}
|
||||
|
||||
/// Grow is only called on full elts, so nelts is also len(elts), unlike
|
||||
/// elsewhere.
|
||||
fn grow<T>(nelts: uint, lo: uint, elts: &mut [Option<T>]) -> ~[Option<T>] {
|
||||
fn grow<T>(nelts: uint, lo: uint, elts: &mut ~[Option<T>]) {
|
||||
assert_eq!(nelts, elts.len());
|
||||
let mut rv = ~[];
|
||||
let newlen = elts.capacity() * 2;
|
||||
elts.reserve(newlen);
|
||||
|
||||
do rv.grow_fn(nelts + 1) |i| {
|
||||
replace(&mut elts[(lo + i) % nelts], None)
|
||||
/* fill with None */
|
||||
for uint::range(elts.len(), elts.capacity()) |_| {
|
||||
elts.push(None);
|
||||
}
|
||||
/* move the former wraparound to the new half */
|
||||
for uint::range(0, lo) |i| {
|
||||
elts.swap(i, nelts + i);
|
||||
}
|
||||
|
||||
rv
|
||||
}
|
||||
|
||||
fn get<'r, T>(elts: &'r [Option<T>], i: uint) -> &'r T {
|
||||
|
Loading…
x
Reference in New Issue
Block a user