diff options
| author | bors <bors@rust-lang.org> | 2018-08-29 20:08:16 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-08-29 20:08:16 +0000 |
| commit | 02cb8f2a4f078025abe6ddba3cff81b383a23973 (patch) | |
| tree | 0e4a68f530d61edb08281b1275034666089c11ae /src/liballoc | |
| parent | e6b35b0e1115f008796e8313574e4a4739b6d39d (diff) | |
| parent | 21d2a6c9868541ec9829ced9a5bae936b18741c5 (diff) | |
| download | rust-02cb8f2a4f078025abe6ddba3cff81b383a23973.tar.gz rust-02cb8f2a4f078025abe6ddba3cff81b383a23973.zip | |
Auto merge of #53564 - MaloJaffre:vecdeque, r=gnzlbg
Reoptimize VecDeque::append ~Unfortunately, I don't know if these changes fix the unsoundness mentioned in #53529, so it is stil a WIP. This is also completely untested. The VecDeque code contains other unsound code: one example : [reading unitialized memory](https://play.rust-lang.org/?gist=6ff47551769af61fd8adc45c44010887&version=nightly&mode=release&edition=2015) (detected by MIRI), so I think this code will need a bigger refactor to make it clearer and safer.~ Note: this is based on #53571. r? @SimonSapin Cc: #53529 #52553 @YorickPeterse @jonas-schievink @Pazzaz @shepmaster.
Diffstat (limited to 'src/liballoc')
| -rw-r--r-- | src/liballoc/collections/vec_deque.rs | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index 571f35a2031..c53549ab85d 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -19,6 +19,7 @@ use core::cmp::Ordering; use core::fmt; +use core::isize; use core::iter::{repeat, FromIterator, FusedIterator}; use core::mem; use core::ops::Bound::{Excluded, Included, Unbounded}; @@ -202,6 +203,33 @@ impl<T> VecDeque<T> { len); } + /// Copies all values from `src` to the back of `self`, wrapping around if needed. + /// + /// # Safety + /// + /// The capacity must be sufficient to hold self.len() + src.len() elements. + /// If so, this function never panics. + #[inline] + unsafe fn copy_slice(&mut self, src: &[T]) { + /// This is guaranteed by `RawVec`. + debug_assert!(self.capacity() <= isize::MAX as usize); + + let expected_new_len = self.len() + src.len(); + debug_assert!(self.capacity() >= expected_new_len); + + 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()); + debug_assert!(self.len() == expected_new_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). @@ -1024,7 +1052,7 @@ impl<T> VecDeque<T> { iter: Iter { tail: drain_tail, head: drain_head, - ring: unsafe { self.buffer_as_mut_slice() }, + ring: unsafe { self.buffer_as_slice() }, }, } } @@ -1834,8 +1862,22 @@ 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(..)); + unsafe { + // Guarantees there is space in `self` for `other`. + self.reserve(other.len()); + + { + let (src_high, src_low) = other.as_slices(); + + // This is only safe because copy_slice never panics when capacity is sufficient. + 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. @@ -2593,8 +2635,8 @@ impl<T> From<VecDeque<T>> for Vec<T> { let mut right_offset = 0; for i in left_edge..right_edge { right_offset = (i - left_edge) % (cap - right_edge); - let src: isize = (right_edge + right_offset) as isize; - ptr::swap(buf.add(i), buf.offset(src)); + let src = right_edge + right_offset; + ptr::swap(buf.add(i), buf.add(src)); } let n_ops = right_edge - left_edge; left_edge += n_ops; |
