]> git.lizzy.rs Git - rust.git/commitdiff
deque: Move the shorter part when growing
authorblake2-ppc <blake2-ppc>
Sat, 6 Jul 2013 03:42:45 +0000 (05:42 +0200)
committerblake2-ppc <blake2-ppc>
Sat, 6 Jul 2013 05:26:04 +0000 (07:26 +0200)
The deque is split at the marker lo, or logical index 0. Move the
shortest part (split by lo) when growing. This way add_front is just as
fast as add_back, on average.

src/libextra/deque.rs

index e8f8a31d7be0b3e5ce3a2f9f09041a28d9ebf5ff..3dfc90002d3c7d286a7d4b534eeca480a5621a79 100644 (file)
@@ -108,7 +108,7 @@ pub fn pop_back(&mut self) -> T {
     /// Prepend an element to the deque
     pub fn add_front(&mut self, t: T) {
         if self.nelts == self.elts.len() {
-            grow(self.nelts, self.lo, &mut self.elts);
+            grow(self.nelts, &mut self.lo, &mut self.elts);
         }
         if self.lo == 0u {
             self.lo = self.elts.len() - 1u;
@@ -120,7 +120,7 @@ pub fn add_front(&mut self, t: T) {
     /// Append an element to the deque
     pub fn add_back(&mut self, t: T) {
         if self.nelts == self.elts.len() {
-            grow(self.nelts, self.lo, &mut self.elts);
+            grow(self.nelts, &mut self.lo, &mut self.elts);
         }
         let hi = self.raw_index(self.nelts);
         self.elts[hi] = Some(t);
@@ -230,18 +230,36 @@ pub struct DequeMutRevIterator<'self, T> {
 
 /// 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>]) {
+fn grow<T>(nelts: uint, loptr: &mut uint, elts: &mut ~[Option<T>]) {
     assert_eq!(nelts, elts.len());
-    let newlen = elts.capacity() * 2;
+    let lo = *loptr;
+    let newlen = nelts * 2;
     elts.reserve(newlen);
 
     /* 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);
+
+    /*
+      Move the shortest half into the newly reserved area.
+      lo ---->|
+      nelts ----------->|
+        [o o o|o o o o o]
+      A [. . .|o o o o o o o o|. . . . .]
+      B [o o o|. . . . . . . .|o o o o o]
+     */
+
+    assert!(newlen - nelts/2 >= nelts);
+    if lo <= (nelts - lo) { // A
+        for uint::range(0, lo) |i| {
+            elts.swap(i, nelts + i);
+        }
+    } else {                // B
+        for uint::range(lo, nelts) |i| {
+            elts.swap(i, newlen - nelts + i);
+        }
+        *loptr += newlen - nelts;
     }
 }