Skip to content

Commit 45be6fc

Browse files
committed
Implement drain over a range for VecDeque
1 parent 3f002a4 commit 45be6fc

File tree

1 file changed

+271
-14
lines changed

1 file changed

+271
-14
lines changed

src/libcollections/vec_deque.rs

+271-14
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use core::cmp;
3030

3131
use alloc::raw_vec::RawVec;
3232

33+
use super::range::RangeArgument;
34+
3335
const INITIAL_CAPACITY: usize = 7; // 2^3 - 1
3436
const MINIMUM_CAPACITY: usize = 1; // 2 - 1
3537

@@ -159,6 +161,117 @@ impl<T> VecDeque<T> {
159161
len);
160162
}
161163

164+
/// Copies a potentially wrapping block of memory len long from src to dest.
165+
/// (abs(dst - src) + len) must be no larger than cap() (There must be at
166+
/// most one continuous overlapping region between src and dest).
167+
unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) {
168+
debug_assert!(
169+
(if src <= dst { dst - src } else { src - dst }) + len <= self.cap(),
170+
"dst={} src={} len={} cap={}", dst, src, len, self.cap());
171+
172+
if src == dst || len == 0 { return }
173+
174+
let dst_after_src = self.wrap_sub(dst, src) < len;
175+
176+
let src_pre_wrap_len = self.cap() - src;
177+
let dst_pre_wrap_len = self.cap() - dst;
178+
let src_wraps = src_pre_wrap_len < len;
179+
let dst_wraps = dst_pre_wrap_len < len;
180+
181+
match (dst_after_src, src_wraps, dst_wraps) {
182+
(_, false, false) => {
183+
// src doesn't wrap, dst doesn't wrap
184+
//
185+
// S . . .
186+
// 1 [_ _ A A B B C C _]
187+
// 2 [_ _ A A A A B B _]
188+
// D . . .
189+
//
190+
self.copy(dst, src, len);
191+
}
192+
(false, false, true) => {
193+
// dst before src, src doesn't wrap, dst wraps
194+
//
195+
// S . . .
196+
// 1 [A A B B _ _ _ C C]
197+
// 2 [A A B B _ _ _ A A]
198+
// 3 [B B B B _ _ _ A A]
199+
// . . D .
200+
//
201+
self.copy(dst, src, dst_pre_wrap_len);
202+
self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
203+
}
204+
(true, false, true) => {
205+
// src before dst, src doesn't wrap, dst wraps
206+
//
207+
// S . . .
208+
// 1 [C C _ _ _ A A B B]
209+
// 2 [B B _ _ _ A A B B]
210+
// 3 [B B _ _ _ A A A A]
211+
// . . D .
212+
//
213+
self.copy(0, src + dst_pre_wrap_len, len - dst_pre_wrap_len);
214+
self.copy(dst, src, dst_pre_wrap_len);
215+
}
216+
(false, true, false) => {
217+
// dst before src, src wraps, dst doesn't wrap
218+
//
219+
// . . S .
220+
// 1 [C C _ _ _ A A B B]
221+
// 2 [C C _ _ _ B B B B]
222+
// 3 [C C _ _ _ B B C C]
223+
// D . . .
224+
//
225+
self.copy(dst, src, src_pre_wrap_len);
226+
self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
227+
}
228+
(true, true, false) => {
229+
// src before dst, src wraps, dst doesn't wrap
230+
//
231+
// . . S .
232+
// 1 [A A B B _ _ _ C C]
233+
// 2 [A A A A _ _ _ C C]
234+
// 3 [C C A A _ _ _ C C]
235+
// D . . .
236+
//
237+
self.copy(dst + src_pre_wrap_len, 0, len - src_pre_wrap_len);
238+
self.copy(dst, src, src_pre_wrap_len);
239+
}
240+
(false, true, true) => {
241+
// dst before src, src wraps, dst wraps
242+
//
243+
// . . . S .
244+
// 1 [A B C D _ E F G H]
245+
// 2 [A B C D _ E G H H]
246+
// 3 [A B C D _ E G H A]
247+
// 4 [B C C D _ E G H A]
248+
// . . D . .
249+
//
250+
debug_assert!(dst_pre_wrap_len > src_pre_wrap_len);
251+
let delta = dst_pre_wrap_len - src_pre_wrap_len;
252+
self.copy(dst, src, src_pre_wrap_len);
253+
self.copy(dst + src_pre_wrap_len, 0, delta);
254+
self.copy(0, delta, len - dst_pre_wrap_len);
255+
}
256+
(true, true, true) => {
257+
// src before dst, src wraps, dst wraps
258+
//
259+
// . . S . .
260+
// 1 [A B C D _ E F G H]
261+
// 2 [A A B D _ E F G H]
262+
// 3 [H A B D _ E F G H]
263+
// 4 [H A B D _ E F F G]
264+
// . . . D .
265+
//
266+
debug_assert!(src_pre_wrap_len > dst_pre_wrap_len);
267+
let delta = src_pre_wrap_len - dst_pre_wrap_len;
268+
self.copy(delta, 0, len - src_pre_wrap_len);
269+
self.copy(0, self.cap() - delta, delta);
270+
self.copy(dst, src, dst_pre_wrap_len);
271+
}
272+
}
273+
}
274+
162275
/// Frobs the head and tail sections around to handle the fact that we
163276
/// just reallocated. Unsafe because it trusts old_cap.
164277
#[inline]
@@ -601,8 +714,18 @@ impl<T> VecDeque<T> {
601714
#[stable(feature = "rust1", since = "1.0.0")]
602715
pub fn is_empty(&self) -> bool { self.len() == 0 }
603716

604-
/// Creates a draining iterator that clears the `VecDeque` and iterates over
605-
/// the removed items from start to end.
717+
/// Create a draining iterator that removes the specified range in the
718+
/// `VecDeque` and yields the removed items from start to end. The element
719+
/// range is removed even if the iterator is not consumed until the end.
720+
///
721+
/// Note: It is unspecified how many elements are removed from the deque,
722+
/// if the `Drain` value is not dropped, but the borrow it holds expires
723+
/// (eg. due to mem::forget).
724+
///
725+
/// # Panics
726+
///
727+
/// Panics if the starting point is greater than the end point or if
728+
/// the end point is greater than the length of the vector.
606729
///
607730
/// # Examples
608731
///
@@ -611,18 +734,66 @@ impl<T> VecDeque<T> {
611734
///
612735
/// use std::collections::VecDeque;
613736
///
737+
/// // draining using `..` clears the whole deque.
614738
/// let mut v = VecDeque::new();
615739
/// v.push_back(1);
616-
/// assert_eq!(v.drain().next(), Some(1));
740+
/// assert_eq!(v.drain(..).next(), Some(1));
617741
/// assert!(v.is_empty());
618742
/// ```
619743
#[inline]
620744
#[unstable(feature = "drain",
621745
reason = "matches collection reform specification, waiting for dust to settle",
622746
issue = "27711")]
623-
pub fn drain(&mut self) -> Drain<T> {
747+
pub fn drain<R>(&mut self, range: R) -> Drain<T> where R: RangeArgument<usize> {
748+
// Memory safety
749+
//
750+
// When the Drain is first created, the source deque is shortened to
751+
// make sure no uninitialized or moved-from elements are accessible at
752+
// all if the Drain's destructor never gets to run.
753+
//
754+
// Drain will ptr::read out the values to remove.
755+
// When finished, the remaining data will be copied back to cover the hole,
756+
// and the head/tail values will be restored correctly.
757+
//
758+
let len = self.len();
759+
let start = *range.start().unwrap_or(&0);
760+
let end = *range.end().unwrap_or(&len);
761+
assert!(start <= end, "drain lower bound was too large");
762+
assert!(end <= len, "drain upper bound was too large");
763+
764+
// The deque's elements are parted into three segments:
765+
// * self.tail -> drain_tail
766+
// * drain_tail -> drain_head
767+
// * drain_head -> self.head
768+
//
769+
// T = self.tail; H = self.head; t = drain_tail; h = drain_head
770+
//
771+
// We store drain_tail as self.head, and drain_head and self.head as
772+
// after_tail and after_head respectively on the Drain. This also
773+
// truncates the effective array such that if the Drain is leaked, we
774+
// have forgotten about the potentially moved values after the start of
775+
// the drain.
776+
//
777+
// T t h H
778+
// [. . . o o x x o o . . .]
779+
//
780+
let drain_tail = self.wrap_add(self.tail, start);
781+
let drain_head = self.wrap_add(self.tail, end);
782+
let head = self.head;
783+
784+
// "forget" about the values after the start of the drain until after
785+
// the drain is complete and the Drain destructor is run.
786+
self.head = drain_tail;
787+
624788
Drain {
625-
inner: self,
789+
deque: self as *mut _,
790+
after_tail: drain_head,
791+
after_head: head,
792+
iter: Iter {
793+
tail: drain_tail,
794+
head: drain_head,
795+
ring: unsafe { self.buffer_as_mut_slice() },
796+
},
626797
}
627798
}
628799

@@ -641,7 +812,7 @@ impl<T> VecDeque<T> {
641812
#[stable(feature = "rust1", since = "1.0.0")]
642813
#[inline]
643814
pub fn clear(&mut self) {
644-
self.drain();
815+
self.drain(..);
645816
}
646817

647818
/// Provides a reference to the front element, or `None` if the sequence is
@@ -1386,7 +1557,7 @@ impl<T> VecDeque<T> {
13861557
issue = "27765")]
13871558
pub fn append(&mut self, other: &mut Self) {
13881559
// naive impl
1389-
self.extend(other.drain());
1560+
self.extend(other.drain(..));
13901561
}
13911562

13921563
/// Retains only the elements specified by the predicate.
@@ -1623,15 +1794,56 @@ impl<T> ExactSizeIterator for IntoIter<T> {}
16231794
reason = "matches collection reform specification, waiting for dust to settle",
16241795
issue = "27711")]
16251796
pub struct Drain<'a, T: 'a> {
1626-
inner: &'a mut VecDeque<T>,
1797+
after_tail: usize,
1798+
after_head: usize,
1799+
iter: Iter<'a, T>,
1800+
deque: *mut VecDeque<T>,
16271801
}
16281802

16291803
#[stable(feature = "rust1", since = "1.0.0")]
16301804
impl<'a, T: 'a> Drop for Drain<'a, T> {
16311805
fn drop(&mut self) {
16321806
for _ in self.by_ref() {}
1633-
self.inner.head = 0;
1634-
self.inner.tail = 0;
1807+
1808+
let source_deque = unsafe { &mut *self.deque };
1809+
1810+
// T = source_deque_tail; H = source_deque_head; t = drain_tail; h = drain_head
1811+
//
1812+
// T t h H
1813+
// [. . . o o x x o o . . .]
1814+
//
1815+
let orig_tail = source_deque.tail;
1816+
let drain_tail = source_deque.head;
1817+
let drain_head = self.after_tail;
1818+
let orig_head = self.after_head;
1819+
1820+
let tail_len = count(orig_tail, drain_tail, source_deque.cap());
1821+
let head_len = count(drain_head, orig_head, source_deque.cap());
1822+
1823+
// Restore the original head value
1824+
source_deque.head = orig_head;
1825+
1826+
match (tail_len, head_len) {
1827+
(0, 0) => {
1828+
source_deque.head = 0;
1829+
source_deque.tail = 0;
1830+
}
1831+
(0, _) => {
1832+
source_deque.tail = drain_head;
1833+
}
1834+
(_, 0) => {
1835+
source_deque.head = drain_tail;
1836+
}
1837+
_ => unsafe {
1838+
if tail_len <= head_len {
1839+
source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
1840+
source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
1841+
} else {
1842+
source_deque.head = source_deque.wrap_add(drain_tail, head_len);
1843+
source_deque.wrap_copy(drain_tail, drain_head, head_len);
1844+
}
1845+
}
1846+
}
16351847
}
16361848
}
16371849

@@ -1641,21 +1853,28 @@ impl<'a, T: 'a> Iterator for Drain<'a, T> {
16411853

16421854
#[inline]
16431855
fn next(&mut self) -> Option<T> {
1644-
self.inner.pop_front()
1856+
self.iter.next().map(|elt|
1857+
unsafe {
1858+
ptr::read(elt)
1859+
}
1860+
)
16451861
}
16461862

16471863
#[inline]
16481864
fn size_hint(&self) -> (usize, Option<usize>) {
1649-
let len = self.inner.len();
1650-
(len, Some(len))
1865+
self.iter.size_hint()
16511866
}
16521867
}
16531868

16541869
#[stable(feature = "rust1", since = "1.0.0")]
16551870
impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
16561871
#[inline]
16571872
fn next_back(&mut self) -> Option<T> {
1658-
self.inner.pop_back()
1873+
self.iter.next_back().map(|elt|
1874+
unsafe {
1875+
ptr::read(elt)
1876+
}
1877+
)
16591878
}
16601879
}
16611880

@@ -1965,6 +2184,44 @@ mod tests {
19652184
}
19662185
}
19672186

2187+
#[test]
2188+
fn test_drain() {
2189+
let mut tester: VecDeque<usize> = VecDeque::with_capacity(7);
2190+
2191+
let cap = tester.capacity();
2192+
for len in 0..cap + 1 {
2193+
for tail in 0..cap + 1 {
2194+
for drain_start in 0..len + 1 {
2195+
for drain_end in drain_start..len + 1 {
2196+
tester.tail = tail;
2197+
tester.head = tail;
2198+
for i in 0..len {
2199+
tester.push_back(i);
2200+
}
2201+
2202+
// Check that we drain the correct values
2203+
let drained: VecDeque<_> =
2204+
tester.drain(drain_start..drain_end).collect();
2205+
let drained_expected: VecDeque<_> =
2206+
(drain_start..drain_end).collect();
2207+
assert_eq!(drained, drained_expected);
2208+
2209+
// We shouldn't have changed the capacity or made the
2210+
// head or tail out of bounds
2211+
assert_eq!(tester.capacity(), cap);
2212+
assert!(tester.tail < tester.cap());
2213+
assert!(tester.head < tester.cap());
2214+
2215+
// We should see the correct values in the VecDeque
2216+
let expected: VecDeque<_> =
2217+
(0..drain_start).chain(drain_end..len).collect();
2218+
assert_eq!(expected, tester);
2219+
}
2220+
}
2221+
}
2222+
}
2223+
}
2224+
19682225
#[test]
19692226
fn test_shrink_to_fit() {
19702227
// This test checks that every single combination of head and tail position,

0 commit comments

Comments
 (0)