Skip to content

Commit 4223a23

Browse files
author
Ulrik Sverdrup
committed
collections: Implement vec::drain(range) according to RFC 574
Old `.drain()` on vec is performed using `.drain(..)` now. [breaking-change]
1 parent 4dbb8e7 commit 4223a23

File tree

4 files changed

+139
-85
lines changed

4 files changed

+139
-85
lines changed

src/libcollections/binary_heap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ impl<T: Ord> BinaryHeap<T> {
546546
#[unstable(feature = "collections",
547547
reason = "matches collection reform specification, waiting for dust to settle")]
548548
pub fn drain(&mut self) -> Drain<T> {
549-
Drain { iter: self.data.drain() }
549+
Drain { iter: self.data.drain(..) }
550550
}
551551

552552
/// Drops all items from the binary heap.

src/libcollections/vec.rs

Lines changed: 104 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ use core::usize;
6969

7070
use borrow::{Cow, IntoCow};
7171

72+
use super::range::RangeArgument;
73+
7274
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
7375
static MAX_MEMORY_SIZE: usize = isize::MAX as usize;
7476

@@ -718,36 +720,61 @@ impl<T> Vec<T> {
718720
unsafe { other.set_len(0); }
719721
}
720722

721-
/// Creates a draining iterator that clears the `Vec` and iterates over
722-
/// the removed items from start to end.
723+
/// Create a draining iterator that removes the specified range in the vector
724+
/// and yields the removed items from start to end. The element range is
725+
/// removed even if the iterator is not consumed until the end.
726+
///
727+
/// Note: It is unspecified how many elements are removed from the vector,
728+
/// if the `Drain` value is leaked.
729+
///
730+
/// # Panics
731+
///
732+
/// Panics if the starting point is greater than the end point or if
733+
/// the end point is greater than the length of the vector.
723734
///
724735
/// # Examples
725736
///
726737
/// ```
727738
/// # #![feature(collections)]
728-
/// let mut v = vec!["a".to_string(), "b".to_string()];
729-
/// for s in v.drain() {
730-
/// // s has type String, not &String
731-
/// println!("{}", s);
732-
/// }
733-
/// assert!(v.is_empty());
739+
///
740+
/// // Draining using `..` clears the whole vector.
741+
/// let mut v = vec![1, 2, 3];
742+
/// let u: Vec<_> = v.drain(..).collect();
743+
/// assert_eq!(v, &[]);
744+
/// assert_eq!(u, &[1, 2, 3]);
734745
/// ```
735-
#[inline]
736746
#[unstable(feature = "collections",
737-
reason = "matches collection reform specification, waiting for dust to settle")]
738-
pub fn drain(&mut self) -> Drain<T> {
747+
reason = "recently added, matches RFC")]
748+
pub fn drain<R>(&mut self, range: R) -> Drain<T> where
749+
R: RangeArgument<usize>,
750+
{
751+
// Memory safety
752+
//
753+
// When the Drain is first created, it shortens the length of
754+
// the source vector to make sure no uninitalized or moved-from elements
755+
// are accessible at all if the Drain's destructor never gets to run.
756+
//
757+
// Drain will ptr::read out the values to remove.
758+
// When finished, remaining tail of the vec is copied back to cover
759+
// the hole, and the vector length is restored to the new length.
760+
//
761+
let len = self.len();
762+
let start = *range.start().unwrap_or(&0);
763+
let end = *range.end().unwrap_or(&len);
764+
assert!(start <= end);
765+
assert!(end <= len);
766+
739767
unsafe {
740-
let begin = *self.ptr as *const T;
741-
let end = if mem::size_of::<T>() == 0 {
742-
(*self.ptr as usize + self.len()) as *const T
743-
} else {
744-
(*self.ptr).offset(self.len() as isize) as *const T
745-
};
746-
self.set_len(0);
768+
// set self.vec length's to start, to be safe in case Drain is leaked
769+
self.set_len(start);
770+
let range_slice = slice::from_raw_parts(self.as_ptr().offset(start as isize),
771+
end - start);
747772
Drain {
748-
ptr: begin,
749-
end: end,
750-
marker: PhantomData,
773+
tail_start: end,
774+
tail_len: len - end,
775+
iter: range_slice.iter(),
776+
vec: self as *mut _,
777+
_marker: PhantomData,
751778
}
752779
}
753780
}
@@ -1799,95 +1826,92 @@ impl<T> Drop for IntoIter<T> {
17991826
}
18001827
}
18011828

1802-
/// An iterator that drains a vector.
1803-
#[unsafe_no_drop_flag]
1804-
#[unstable(feature = "collections",
1805-
reason = "recently added as part of collections reform 2")]
1806-
pub struct Drain<'a, T:'a> {
1807-
ptr: *const T,
1808-
end: *const T,
1809-
marker: PhantomData<&'a T>,
1829+
/// A draining iterator for `Vec<T>`.
1830+
#[unstable(feature = "collections", reason = "recently added")]
1831+
pub struct Drain<'a, T: 'a>
1832+
{
1833+
/// Index of tail to preserve
1834+
tail_start: usize,
1835+
/// Length of tail
1836+
tail_len: usize,
1837+
/// Current remaining range to remove
1838+
iter: slice::Iter<'a, T>,
1839+
vec: *mut Vec<T>,
1840+
_marker: PhantomData<&'a mut Vec<T>>,
18101841
}
18111842

18121843
unsafe impl<'a, T: Sync> Sync for Drain<'a, T> {}
18131844
unsafe impl<'a, T: Send> Send for Drain<'a, T> {}
18141845

18151846
#[stable(feature = "rust1", since = "1.0.0")]
1816-
impl<'a, T> Iterator for Drain<'a, T> {
1847+
impl<'a, T> Iterator for Drain<'a, T>
1848+
{
18171849
type Item = T;
18181850

18191851
#[inline]
1820-
fn next(&mut self) -> Option<T> {
1821-
unsafe {
1822-
if self.ptr == self.end {
1823-
None
1824-
} else {
1825-
if mem::size_of::<T>() == 0 {
1826-
// purposefully don't use 'ptr.offset' because for
1827-
// vectors with 0-size elements this would return the
1828-
// same pointer.
1829-
self.ptr = mem::transmute(self.ptr as usize + 1);
1830-
1831-
// Use a non-null pointer value
1832-
Some(ptr::read(EMPTY as *mut T))
1833-
} else {
1834-
let old = self.ptr;
1835-
self.ptr = self.ptr.offset(1);
1836-
1837-
Some(ptr::read(old))
1852+
fn next(&mut self) -> Option<T>
1853+
{
1854+
match self.iter.next() {
1855+
None => None,
1856+
Some(elt) => {
1857+
unsafe {
1858+
Some(ptr::read(elt as *const _))
18381859
}
18391860
}
18401861
}
18411862
}
18421863

1843-
#[inline]
1844-
fn size_hint(&self) -> (usize, Option<usize>) {
1845-
let diff = (self.end as usize) - (self.ptr as usize);
1846-
let size = mem::size_of::<T>();
1847-
let exact = diff / (if size == 0 {1} else {size});
1848-
(exact, Some(exact))
1864+
fn size_hint(&self) -> (usize, Option<usize>)
1865+
{
1866+
self.iter.size_hint()
18491867
}
18501868
}
18511869

18521870
#[stable(feature = "rust1", since = "1.0.0")]
1853-
impl<'a, T> DoubleEndedIterator for Drain<'a, T> {
1871+
impl<'a, T> DoubleEndedIterator for Drain<'a, T>
1872+
{
18541873
#[inline]
1855-
fn next_back(&mut self) -> Option<T> {
1856-
unsafe {
1857-
if self.end == self.ptr {
1858-
None
1859-
} else {
1860-
if mem::size_of::<T>() == 0 {
1861-
// See above for why 'ptr.offset' isn't used
1862-
self.end = mem::transmute(self.end as usize - 1);
1863-
1864-
// Use a non-null pointer value
1865-
Some(ptr::read(EMPTY as *mut T))
1866-
} else {
1867-
self.end = self.end.offset(-1);
1868-
1869-
Some(ptr::read(self.end))
1874+
fn next_back(&mut self) -> Option<T>
1875+
{
1876+
match self.iter.next_back() {
1877+
None => None,
1878+
Some(elt) => {
1879+
unsafe {
1880+
Some(ptr::read(elt as *const _))
18701881
}
18711882
}
18721883
}
18731884
}
18741885
}
18751886

1876-
#[stable(feature = "rust1", since = "1.0.0")]
1877-
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
1878-
18791887
#[unsafe_destructor]
18801888
#[stable(feature = "rust1", since = "1.0.0")]
1881-
impl<'a, T> Drop for Drain<'a, T> {
1882-
fn drop(&mut self) {
1883-
// self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
1884-
// so we can use #[unsafe_no_drop_flag].
1885-
1886-
// destroy the remaining elements
1887-
for _x in self.by_ref() {}
1889+
impl<'a, T> Drop for Drain<'a, T>
1890+
{
1891+
fn drop(&mut self)
1892+
{
1893+
// exhaust self first
1894+
while let Some(_) = self.next() { }
1895+
1896+
if self.tail_len > 0 {
1897+
unsafe {
1898+
let source_vec = &mut *self.vec;
1899+
// memmove back untouched tail, update to new length
1900+
let start = source_vec.len();
1901+
let tail = self.tail_start;
1902+
let src = source_vec.as_ptr().offset(tail as isize);
1903+
let dst = source_vec.as_mut_ptr().offset(start as isize);
1904+
ptr::copy(src, dst, self.tail_len);
1905+
source_vec.set_len(start + self.tail_len);
1906+
}
1907+
}
18881908
}
18891909
}
18901910

1911+
1912+
#[stable(feature = "rust1", since = "1.0.0")]
1913+
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
1914+
18911915
////////////////////////////////////////////////////////////////////////////////
18921916
// Conversion from &[T] to &Vec<T>
18931917
////////////////////////////////////////////////////////////////////////////////

src/libcollections/vec_map.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl<V> VecMap<V> {
418418
}
419419
let filter: fn((usize, Option<V>)) -> Option<(usize, V)> = filter; // coerce to fn ptr
420420

421-
Drain { iter: self.v.drain().enumerate().filter_map(filter) }
421+
Drain { iter: self.v.drain(..).enumerate().filter_map(filter) }
422422
}
423423

424424
/// Returns the number of elements in the map.

src/libcollectionstest/vec.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ fn test_move_items_zero_sized() {
460460
fn test_drain_items() {
461461
let mut vec = vec![1, 2, 3];
462462
let mut vec2 = vec![];
463-
for i in vec.drain() {
463+
for i in vec.drain(..) {
464464
vec2.push(i);
465465
}
466466
assert_eq!(vec, []);
@@ -471,7 +471,7 @@ fn test_drain_items() {
471471
fn test_drain_items_reverse() {
472472
let mut vec = vec![1, 2, 3];
473473
let mut vec2 = vec![];
474-
for i in vec.drain().rev() {
474+
for i in vec.drain(..).rev() {
475475
vec2.push(i);
476476
}
477477
assert_eq!(vec, []);
@@ -482,13 +482,43 @@ fn test_drain_items_reverse() {
482482
fn test_drain_items_zero_sized() {
483483
let mut vec = vec![(), (), ()];
484484
let mut vec2 = vec![];
485-
for i in vec.drain() {
485+
for i in vec.drain(..) {
486486
vec2.push(i);
487487
}
488488
assert_eq!(vec, []);
489489
assert_eq!(vec2, [(), (), ()]);
490490
}
491491

492+
#[test]
493+
#[should_panic]
494+
fn drain_out_of_bounds_1() {
495+
let mut v = vec![1, 2, 3, 4, 5];
496+
v.drain(5..6);
497+
}
498+
499+
#[test]
500+
fn drain_range() {
501+
let mut v = vec![1, 2, 3, 4, 5];
502+
for _ in v.drain(4..) {
503+
}
504+
assert_eq!(v, &[1, 2, 3, 4]);
505+
506+
let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
507+
for _ in v.drain(1..4) {
508+
}
509+
assert_eq!(v, &[1.to_string(), 5.to_string()]);
510+
511+
let mut v: Vec<_> = (1..6).map(|x| x.to_string()).collect();
512+
for _ in v.drain(1..4).rev() {
513+
}
514+
assert_eq!(v, &[1.to_string(), 5.to_string()]);
515+
516+
let mut v: Vec<_> = vec![(); 5];
517+
for _ in v.drain(1..4).rev() {
518+
}
519+
assert_eq!(v, &[(), ()]);
520+
}
521+
492522
#[test]
493523
fn test_into_boxed_slice() {
494524
let xs = vec![1, 2, 3];

0 commit comments

Comments
 (0)