@@ -69,6 +69,8 @@ use core::usize;
69
69
70
70
use borrow:: { Cow , IntoCow } ;
71
71
72
+ use super :: range:: RangeArgument ;
73
+
72
74
// FIXME- fix places which assume the max vector allowed has memory usize::MAX.
73
75
static MAX_MEMORY_SIZE : usize = isize:: MAX as usize ;
74
76
@@ -714,36 +716,61 @@ impl<T> Vec<T> {
714
716
unsafe { other. set_len ( 0 ) ; }
715
717
}
716
718
717
- /// Creates a draining iterator that clears the `Vec` and iterates over
718
- /// the removed items from start to end.
719
+ /// Create a draining iterator that removes the specified range in the vector
720
+ /// and yields the removed items from start to end. The element range is
721
+ /// removed even if the iterator is not consumed until the end.
722
+ ///
723
+ /// Note: It is unspecified how many elements are removed from the vector,
724
+ /// if the `Drain` value is leaked.
725
+ ///
726
+ /// # Panics
727
+ ///
728
+ /// Panics if the starting point is greater than the end point or if
729
+ /// the end point is greater than the length of the vector.
719
730
///
720
731
/// # Examples
721
732
///
722
733
/// ```
723
- /// # #![feature(collections )]
724
- /// let mut v = vec!["a".to_string(), "b".to_string()];
725
- /// for s in v.drain() {
726
- /// // s has type String, not &String
727
- /// println!("{}", s );
728
- /// }
729
- /// assert!(v.is_empty() );
734
+ /// # #![feature(collections_drain, collections_range )]
735
+ ///
736
+ /// // Draining using `..` clears the whole vector.
737
+ /// let mut v = vec![1, 2, 3];
738
+ /// let u: Vec<_> = v.drain(..).collect( );
739
+ /// assert_eq!(v, &[]);
740
+ /// assert_eq!(u, &[1, 2, 3] );
730
741
/// ```
731
- #[ inline]
732
- #[ unstable( feature = "collections" ,
733
- reason = "matches collection reform specification, waiting for dust to settle" ) ]
734
- pub fn drain ( & mut self ) -> Drain < T > {
742
+ #[ unstable( feature = "collections_drain" ,
743
+ reason = "recently added, matches RFC" ) ]
744
+ pub fn drain < R > ( & mut self , range : R ) -> Drain < T > where R : RangeArgument < usize > {
745
+ // Memory safety
746
+ //
747
+ // When the Drain is first created, it shortens the length of
748
+ // the source vector to make sure no uninitalized or moved-from elements
749
+ // are accessible at all if the Drain's destructor never gets to run.
750
+ //
751
+ // Drain will ptr::read out the values to remove.
752
+ // When finished, remaining tail of the vec is copied back to cover
753
+ // the hole, and the vector length is restored to the new length.
754
+ //
755
+ let len = self . len ( ) ;
756
+ let start = * range. start ( ) . unwrap_or ( & 0 ) ;
757
+ let end = * range. end ( ) . unwrap_or ( & len) ;
758
+ assert ! ( start <= end) ;
759
+ assert ! ( end <= len) ;
760
+
735
761
unsafe {
736
- let begin = * self . ptr as * const T ;
737
- let end = if mem :: size_of :: < T > ( ) == 0 {
738
- ( * self . ptr as usize + self . len ( ) ) as * const T
739
- } else {
740
- ( * self . ptr ) . offset ( self . len ( ) as isize ) as * const T
741
- } ;
742
- self . set_len ( 0 ) ;
762
+ // set self.vec length's to start, to be safe in case Drain is leaked
763
+ self . set_len ( start ) ;
764
+ // Use the borrow in the IterMut to indicate borrowing behavior of the
765
+ // whole Drain iterator (like &mut T).
766
+ let range_slice = slice :: from_raw_parts_mut (
767
+ self . as_mut_ptr ( ) . offset ( start as isize ) ,
768
+ end - start ) ;
743
769
Drain {
744
- ptr : begin,
745
- end : end,
746
- marker : PhantomData ,
770
+ tail_start : end,
771
+ tail_len : len - end,
772
+ iter : range_slice. iter_mut ( ) ,
773
+ vec : self as * mut _ ,
747
774
}
748
775
}
749
776
}
@@ -1795,14 +1822,16 @@ impl<T> Drop for IntoIter<T> {
1795
1822
}
1796
1823
}
1797
1824
1798
- /// An iterator that drains a vector.
1799
- #[ unsafe_no_drop_flag]
1800
- #[ unstable( feature = "collections" ,
1801
- reason = "recently added as part of collections reform 2" ) ]
1802
- pub struct Drain < ' a , T : ' a > {
1803
- ptr : * const T ,
1804
- end : * const T ,
1805
- marker : PhantomData < & ' a T > ,
1825
+ /// A draining iterator for `Vec<T>`.
1826
+ #[ unstable( feature = "collections_drain" , reason = "recently added" ) ]
1827
+ pub struct Drain < ' a , T : ' a > {
1828
+ /// Index of tail to preserve
1829
+ tail_start : usize ,
1830
+ /// Length of tail
1831
+ tail_len : usize ,
1832
+ /// Current remaining range to remove
1833
+ iter : slice:: IterMut < ' a , T > ,
1834
+ vec : * mut Vec < T > ,
1806
1835
}
1807
1836
1808
1837
unsafe impl < ' a , T : Sync > Sync for Drain < ' a , T > { }
@@ -1814,76 +1843,56 @@ impl<'a, T> Iterator for Drain<'a, T> {
1814
1843
1815
1844
#[ inline]
1816
1845
fn next ( & mut self ) -> Option < T > {
1817
- unsafe {
1818
- if self . ptr == self . end {
1819
- None
1820
- } else {
1821
- if mem:: size_of :: < T > ( ) == 0 {
1822
- // purposefully don't use 'ptr.offset' because for
1823
- // vectors with 0-size elements this would return the
1824
- // same pointer.
1825
- self . ptr = mem:: transmute ( self . ptr as usize + 1 ) ;
1826
-
1827
- // Use a non-null pointer value
1828
- Some ( ptr:: read ( EMPTY as * mut T ) )
1829
- } else {
1830
- let old = self . ptr ;
1831
- self . ptr = self . ptr . offset ( 1 ) ;
1832
-
1833
- Some ( ptr:: read ( old) )
1834
- }
1846
+ self . iter . next ( ) . map ( |elt|
1847
+ unsafe {
1848
+ ptr:: read ( elt as * const _ )
1835
1849
}
1836
- }
1850
+ )
1837
1851
}
1838
1852
1839
- #[ inline]
1840
1853
fn size_hint ( & self ) -> ( usize , Option < usize > ) {
1841
- let diff = ( self . end as usize ) - ( self . ptr as usize ) ;
1842
- let size = mem:: size_of :: < T > ( ) ;
1843
- let exact = diff / ( if size == 0 { 1 } else { size} ) ;
1844
- ( exact, Some ( exact) )
1854
+ self . iter . size_hint ( )
1845
1855
}
1846
1856
}
1847
1857
1848
1858
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1849
1859
impl < ' a , T > DoubleEndedIterator for Drain < ' a , T > {
1850
1860
#[ inline]
1851
1861
fn next_back ( & mut self ) -> Option < T > {
1852
- unsafe {
1853
- if self . end == self . ptr {
1854
- None
1855
- } else {
1856
- if mem:: size_of :: < T > ( ) == 0 {
1857
- // See above for why 'ptr.offset' isn't used
1858
- self . end = mem:: transmute ( self . end as usize - 1 ) ;
1859
-
1860
- // Use a non-null pointer value
1861
- Some ( ptr:: read ( EMPTY as * mut T ) )
1862
- } else {
1863
- self . end = self . end . offset ( -1 ) ;
1864
-
1865
- Some ( ptr:: read ( self . end ) )
1866
- }
1862
+ self . iter . next_back ( ) . map ( |elt|
1863
+ unsafe {
1864
+ ptr:: read ( elt as * const _ )
1867
1865
}
1868
- }
1866
+ )
1869
1867
}
1870
1868
}
1871
1869
1872
- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1873
- impl < ' a , T > ExactSizeIterator for Drain < ' a , T > { }
1874
-
1875
1870
#[ unsafe_destructor]
1876
1871
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1877
1872
impl < ' a , T > Drop for Drain < ' a , T > {
1878
1873
fn drop ( & mut self ) {
1879
- // self.ptr == self.end == mem::POST_DROP_USIZE if drop has already been called,
1880
- // so we can use #[unsafe_no_drop_flag].
1874
+ // exhaust self first
1875
+ while let Some ( _ ) = self . next ( ) { }
1881
1876
1882
- // destroy the remaining elements
1883
- for _x in self . by_ref ( ) { }
1877
+ if self . tail_len > 0 {
1878
+ unsafe {
1879
+ let source_vec = & mut * self . vec ;
1880
+ // memmove back untouched tail, update to new length
1881
+ let start = source_vec. len ( ) ;
1882
+ let tail = self . tail_start ;
1883
+ let src = source_vec. as_ptr ( ) . offset ( tail as isize ) ;
1884
+ let dst = source_vec. as_mut_ptr ( ) . offset ( start as isize ) ;
1885
+ ptr:: copy ( src, dst, self . tail_len ) ;
1886
+ source_vec. set_len ( start + self . tail_len ) ;
1887
+ }
1888
+ }
1884
1889
}
1885
1890
}
1886
1891
1892
+
1893
+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1894
+ impl < ' a , T > ExactSizeIterator for Drain < ' a , T > { }
1895
+
1887
1896
////////////////////////////////////////////////////////////////////////////////
1888
1897
// Conversion from &[T] to &Vec<T>
1889
1898
////////////////////////////////////////////////////////////////////////////////
0 commit comments