@@ -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
@@ -718,36 +720,61 @@ impl<T> Vec<T> {
718
720
unsafe { other. set_len ( 0 ) ; }
719
721
}
720
722
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.
723
734
///
724
735
/// # Examples
725
736
///
726
737
/// ```
727
- /// # #![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() );
738
+ /// # #![feature(collections_drain, collections_range )]
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] );
734
745
/// ```
735
- #[ inline]
736
- #[ unstable( feature = "collections" ,
737
- reason = "matches collection reform specification, waiting for dust to settle" ) ]
738
- pub fn drain ( & mut self ) -> Drain < T > {
746
+ #[ unstable( feature = "collections_drain" ,
747
+ reason = "recently added, matches RFC" ) ]
748
+ pub fn drain < R > ( & mut self , range : R ) -> Drain < T > where R : RangeArgument < usize > {
749
+ // Memory safety
750
+ //
751
+ // When the Drain is first created, it shortens the length of
752
+ // the source vector to make sure no uninitalized or moved-from elements
753
+ // are accessible at all if the Drain's destructor never gets to run.
754
+ //
755
+ // Drain will ptr::read out the values to remove.
756
+ // When finished, remaining tail of the vec is copied back to cover
757
+ // the hole, and the vector length is restored to the new length.
758
+ //
759
+ let len = self . len ( ) ;
760
+ let start = * range. start ( ) . unwrap_or ( & 0 ) ;
761
+ let end = * range. end ( ) . unwrap_or ( & len) ;
762
+ assert ! ( start <= end) ;
763
+ assert ! ( end <= len) ;
764
+
739
765
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 ) ;
766
+ // set self.vec length's to start, to be safe in case Drain is leaked
767
+ self . set_len ( start ) ;
768
+ // Use the borrow in the IterMut to indicate borrowing behavior of the
769
+ // whole Drain iterator (like &mut T).
770
+ let range_slice = slice :: from_raw_parts_mut (
771
+ self . as_mut_ptr ( ) . offset ( start as isize ) ,
772
+ end - start ) ;
747
773
Drain {
748
- ptr : begin,
749
- end : end,
750
- marker : PhantomData ,
774
+ tail_start : end,
775
+ tail_len : len - end,
776
+ iter : range_slice. iter_mut ( ) ,
777
+ vec : self as * mut _ ,
751
778
}
752
779
}
753
780
}
@@ -1799,14 +1826,16 @@ impl<T> Drop for IntoIter<T> {
1799
1826
}
1800
1827
}
1801
1828
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_drain" , reason = "recently added" ) ]
1831
+ pub struct Drain < ' a , T : ' a > {
1832
+ /// Index of tail to preserve
1833
+ tail_start : usize ,
1834
+ /// Length of tail
1835
+ tail_len : usize ,
1836
+ /// Current remaining range to remove
1837
+ iter : slice:: IterMut < ' a , T > ,
1838
+ vec : * mut Vec < T > ,
1810
1839
}
1811
1840
1812
1841
unsafe impl < ' a , T : Sync > Sync for Drain < ' a , T > { }
@@ -1818,76 +1847,56 @@ impl<'a, T> Iterator for Drain<'a, T> {
1818
1847
1819
1848
#[ inline]
1820
1849
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) )
1838
- }
1850
+ self . iter . next ( ) . map ( |elt|
1851
+ unsafe {
1852
+ ptr:: read ( elt as * const _ )
1839
1853
}
1840
- }
1854
+ )
1841
1855
}
1842
1856
1843
- #[ inline]
1844
1857
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) )
1858
+ self . iter . size_hint ( )
1849
1859
}
1850
1860
}
1851
1861
1852
1862
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1853
1863
impl < ' a , T > DoubleEndedIterator for Drain < ' a , T > {
1854
1864
#[ inline]
1855
1865
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 ) )
1870
- }
1866
+ self . iter . next_back ( ) . map ( |elt|
1867
+ unsafe {
1868
+ ptr:: read ( elt as * const _ )
1871
1869
}
1872
- }
1870
+ )
1873
1871
}
1874
1872
}
1875
1873
1876
- #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1877
- impl < ' a , T > ExactSizeIterator for Drain < ' a , T > { }
1878
-
1879
1874
#[ unsafe_destructor]
1880
1875
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
1881
1876
impl < ' a , T > Drop for Drain < ' a , T > {
1882
1877
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].
1878
+ // exhaust self first
1879
+ while let Some ( _ ) = self . next ( ) { }
1885
1880
1886
- // destroy the remaining elements
1887
- for _x in self . by_ref ( ) { }
1881
+ if self . tail_len > 0 {
1882
+ unsafe {
1883
+ let source_vec = & mut * self . vec ;
1884
+ // memmove back untouched tail, update to new length
1885
+ let start = source_vec. len ( ) ;
1886
+ let tail = self . tail_start ;
1887
+ let src = source_vec. as_ptr ( ) . offset ( tail as isize ) ;
1888
+ let dst = source_vec. as_mut_ptr ( ) . offset ( start as isize ) ;
1889
+ ptr:: copy ( src, dst, self . tail_len ) ;
1890
+ source_vec. set_len ( start + self . tail_len ) ;
1891
+ }
1892
+ }
1888
1893
}
1889
1894
}
1890
1895
1896
+
1897
+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1898
+ impl < ' a , T > ExactSizeIterator for Drain < ' a , T > { }
1899
+
1891
1900
////////////////////////////////////////////////////////////////////////////////
1892
1901
// Conversion from &[T] to &Vec<T>
1893
1902
////////////////////////////////////////////////////////////////////////////////
0 commit comments