about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorMaloJaffre <jaffre.malo@gmail.com>2018-08-22 13:18:51 +0200
committerMaloJaffre <jaffre.malo@gmail.com>2018-08-24 17:43:05 +0200
commit11e488b64fed181820280d494d4fcc157ee1adc5 (patch)
treedf895752d0112f6f85baaaef255299acf1245333 /src/liballoc
parent6ce76acae455a32113116cd2f95f8076388fc2d3 (diff)
downloadrust-11e488b64fed181820280d494d4fcc157ee1adc5.tar.gz
rust-11e488b64fed181820280d494d4fcc157ee1adc5.zip
Optimize VecDeque::append
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/collections/vec_deque.rs29
1 files changed, 27 insertions, 2 deletions
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs
index d49cb985774..7c16258e84e 100644
--- a/src/liballoc/collections/vec_deque.rs
+++ b/src/liballoc/collections/vec_deque.rs
@@ -202,6 +202,22 @@ impl<T> VecDeque<T> {
                                  len);
     }
 
+    /// Copies all values from `src` to `self`, wrapping around if needed.
+    /// Assumes capacity is sufficient.
+    #[inline]
+    unsafe fn copy_slice(&mut self, src: &[T]) {
+        let dst_high_ptr = self.ptr().add(self.head);
+        let dst_high_len = self.cap() - self.head;
+
+        let split = cmp::min(src.len(), dst_high_len);
+        let (src_high, src_low) = src.split_at(split);
+
+        ptr::copy_nonoverlapping(src_high.as_ptr(), dst_high_ptr, src_high.len());
+        ptr::copy_nonoverlapping(src_low.as_ptr(), self.ptr(), src_low.len());
+
+        self.head = self.wrap_add(self.head, src.len());
+    }
+
     /// Copies a potentially wrapping block of memory len long from src to dest.
     /// (abs(dst - src) + len) must be no larger than cap() (There must be at
     /// most one continuous overlapping region between src and dest).
@@ -1834,8 +1850,17 @@ impl<T> VecDeque<T> {
     #[inline]
     #[stable(feature = "append", since = "1.4.0")]
     pub fn append(&mut self, other: &mut Self) {
-        // naive impl
-        self.extend(other.drain(..));
+        // Guarantees there is space in `self` for `other
+        self.reserve(other.len());
+
+        unsafe {
+            let (src_high, src_low) = other.as_slices();
+            self.copy_slice(src_low);
+            self.copy_slice(src_high);
+        }
+
+        // Some values now exist in both `other` and `self` but are made inaccessible in `other`.
+        other.tail = other.head;
     }
 
     /// Retains only the elements specified by the predicate.