From 40ce0b7d76fe39c58e4bdf119af33c4d24950077 Mon Sep 17 00:00:00 2001 From: blake2-ppc Date: Sat, 6 Jul 2013 05:42:45 +0200 Subject: [PATCH] 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) --- src/libextra/deque.rs | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/libextra/deque.rs b/src/libextra/deque.rs index a07d9e6fd22a..02d3e81148f1 100644 --- a/src/libextra/deque.rs +++ b/src/libextra/deque.rs @@ -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 Deque { /// 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 Deque { /// 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(nelts: uint, lo: uint, elts: &mut [Option]) -> ~[Option] { +fn grow(nelts: uint, lo: uint, elts: &mut ~[Option]) { 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], i: uint) -> &'r T {