Skip to content

Commit 887f35f

Browse files
committed
Add Vec::splice and String::splice
1 parent 43843d0 commit 887f35f

File tree

6 files changed

+312
-9
lines changed

6 files changed

+312
-9
lines changed

src/libcollections/slice.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -978,13 +978,9 @@ impl<T: Clone> ToOwned for [T] {
978978
self.to_vec()
979979
}
980980

981-
// HACK(japaric): with cfg(test) the inherent `[T]::to_vec`, which is required for this method
982-
// definition, is not available. Since we don't require this method for testing purposes, I'll
983-
// just stub it
984-
// NB see the slice::hack module in slice.rs for more information
985981
#[cfg(test)]
986982
fn to_owned(&self) -> Vec<T> {
987-
panic!("not available with cfg(test)")
983+
hack::to_vec(self)
988984
}
989985
}
990986

src/libcollections/string.rs

+129-1
Original file line numberDiff line numberDiff line change
@@ -1228,7 +1228,7 @@ impl String {
12281228
self.vec.clear()
12291229
}
12301230

1231-
/// Create a draining iterator that removes the specified range in the string
1231+
/// Creates a draining iterator that removes the specified range in the string
12321232
/// and yields the removed chars.
12331233
///
12341234
/// Note: The element range is removed even if the iterator is not
@@ -1286,6 +1286,63 @@ impl String {
12861286
}
12871287
}
12881288

1289+
/// Creates a splicing iterator that removes the specified range in the string,
1290+
/// replaces with the given string, and yields the removed chars.
1291+
/// The given string doesn’t need to be the same length as the range.
1292+
///
1293+
/// Note: The element range is removed even if the iterator is not
1294+
/// consumed until the end.
1295+
///
1296+
/// # Panics
1297+
///
1298+
/// Panics if the starting point or end point do not lie on a [`char`]
1299+
/// boundary, or if they're out of bounds.
1300+
///
1301+
/// [`char`]: ../../std/primitive.char.html
1302+
///
1303+
/// # Examples
1304+
///
1305+
/// Basic usage:
1306+
///
1307+
/// ```
1308+
/// #![feature(splice)]
1309+
/// let mut s = String::from("α is alpha, β is beta");
1310+
/// let beta_offset = s.find('β').unwrap_or(s.len());
1311+
///
1312+
/// // Replace the range up until the β from the string
1313+
/// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
1314+
/// assert_eq!(t, "α is alpha, ");
1315+
/// assert_eq!(s, "Α is capital alpha; β is beta");
1316+
/// ```
1317+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1318+
pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
1319+
where R: RangeArgument<usize>
1320+
{
1321+
// Memory safety
1322+
//
1323+
// The String version of Splice does not have the memory safety issues
1324+
// of the vector version. The data is just plain bytes.
1325+
// Because the range removal happens in Drop, if the Splice iterator is leaked,
1326+
// the removal will not happen.
1327+
let len = self.len();
1328+
let start = *range.start().unwrap_or(&0);
1329+
let end = *range.end().unwrap_or(&len);
1330+
1331+
// Take out two simultaneous borrows. The &mut String won't be accessed
1332+
// until iteration is over, in Drop.
1333+
let self_ptr = self as *mut _;
1334+
// slicing does the appropriate bounds checks
1335+
let chars_iter = self[start..end].chars();
1336+
1337+
Splice {
1338+
start: start,
1339+
end: end,
1340+
iter: chars_iter,
1341+
string: self_ptr,
1342+
replace_with: replace_with
1343+
}
1344+
}
1345+
12891346
/// Converts this `String` into a `Box<str>`.
12901347
///
12911348
/// This will drop any excess capacity.
@@ -1884,3 +1941,74 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
18841941
self.iter.next_back()
18851942
}
18861943
}
1944+
1945+
/// A splicing iterator for `String`.
1946+
///
1947+
/// This struct is created by the [`splice()`] method on [`String`]. See its
1948+
/// documentation for more.
1949+
///
1950+
/// [`splice()`]: struct.String.html#method.splice
1951+
/// [`String`]: struct.String.html
1952+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1953+
pub struct Splice<'a, 'b> {
1954+
/// Will be used as &'a mut String in the destructor
1955+
string: *mut String,
1956+
/// Start of part to remove
1957+
start: usize,
1958+
/// End of part to remove
1959+
end: usize,
1960+
/// Current remaining range to remove
1961+
iter: Chars<'a>,
1962+
replace_with: &'b str,
1963+
}
1964+
1965+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1966+
unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
1967+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1968+
unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}
1969+
1970+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1971+
impl<'a, 'b> Drop for Splice<'a, 'b> {
1972+
fn drop(&mut self) {
1973+
unsafe {
1974+
let vec = (*self.string).as_mut_vec();
1975+
let range_len = self.end - self.start;
1976+
let replacement_len = self.replace_with.len();
1977+
let tail_len = vec.len() - self.end;
1978+
if replacement_len > range_len {
1979+
vec.reserve(replacement_len - range_len);
1980+
}
1981+
if replacement_len != range_len {
1982+
let src = vec.as_ptr().offset(self.end as isize);
1983+
let dst = vec.as_mut_ptr().offset((self.start + replacement_len) as isize);
1984+
ptr::copy(src, dst, tail_len);
1985+
}
1986+
let src = self.replace_with.as_ptr();
1987+
let dst = vec.as_mut_ptr().offset(self.start as isize);
1988+
ptr::copy(src, dst, replacement_len);
1989+
vec.set_len(self.start + replacement_len + tail_len);
1990+
}
1991+
}
1992+
}
1993+
1994+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1995+
impl<'a, 'b> Iterator for Splice<'a, 'b> {
1996+
type Item = char;
1997+
1998+
#[inline]
1999+
fn next(&mut self) -> Option<char> {
2000+
self.iter.next()
2001+
}
2002+
2003+
fn size_hint(&self) -> (usize, Option<usize>) {
2004+
self.iter.size_hint()
2005+
}
2006+
}
2007+
2008+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
2009+
impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
2010+
#[inline]
2011+
fn next_back(&mut self) -> Option<char> {
2012+
self.iter.next_back()
2013+
}
2014+
}

src/libcollections/vec.rs

+163-3
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ impl<T> Vec<T> {
764764
}
765765
}
766766

767-
/// Create a draining iterator that removes the specified range in the vector
767+
/// Creates a draining iterator that removes the specified range in the vector
768768
/// and yields the removed items.
769769
///
770770
/// Note 1: The element range is removed even if the iterator is not
@@ -826,6 +826,53 @@ impl<T> Vec<T> {
826826
}
827827
}
828828

829+
/// Creates a splicing iterator that replaces the specified range in the vector
830+
/// with the given `replace_with` iterator and yields the removed items.
831+
/// `replace_with` does not need to be the same length as `range`.
832+
///
833+
/// Note 1: The element range is removed even if the iterator is not
834+
/// consumed until the end.
835+
///
836+
/// Note 2: It is unspecified how many elements are removed from the vector,
837+
/// if the `Splice` value is leaked.
838+
///
839+
/// Note 3: The input iterator `replace_with` is only consumed
840+
/// when the `Splice` value is dropped.
841+
///
842+
/// Note 4: This is optimal if:
843+
///
844+
/// * The tail (elements in the vector after `range`) is empty,
845+
/// * or `replace_with` yields fewer elements than `range`’s length
846+
/// * or the lower bound of its `size_hint()` is exact.
847+
///
848+
/// Otherwise, a temporary vector is allocated and the tail is moved twice.
849+
///
850+
/// # Panics
851+
///
852+
/// Panics if the starting point is greater than the end point or if
853+
/// the end point is greater than the length of the vector.
854+
///
855+
/// # Examples
856+
///
857+
/// ```
858+
/// #![feature(splice)]
859+
/// let mut v = vec![1, 2, 3];
860+
/// let new = [7, 8];
861+
/// let u: Vec<_> = v.splice(..2, new.iter().cloned()).collect();
862+
/// assert_eq!(v, &[7, 8, 3]);
863+
/// assert_eq!(u, &[1, 2]);
864+
/// ```
865+
#[inline]
866+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
867+
pub fn splice<R, I>(&mut self, range: R, replace_with: I) -> Splice<I::IntoIter>
868+
where R: RangeArgument<usize>, I: IntoIterator<Item=T>
869+
{
870+
Splice {
871+
drain: self.drain(range),
872+
replace_with: replace_with.into_iter(),
873+
}
874+
}
875+
829876
/// Clears the vector, removing all values.
830877
///
831878
/// # Examples
@@ -1696,7 +1743,7 @@ impl<T> Drop for IntoIter<T> {
16961743
}
16971744
}
16981745

1699-
/// A draining iterator for `Vec<T>`.
1746+
/// A draining iterator for `Vec<T>`. See the [`Vec::drain`](struct.Vec.html#method.drain) method.
17001747
#[stable(feature = "drain", since = "1.6.0")]
17011748
pub struct Drain<'a, T: 'a> {
17021749
/// Index of tail to preserve
@@ -1756,6 +1803,119 @@ impl<'a, T> Drop for Drain<'a, T> {
17561803
}
17571804
}
17581805

1759-
17601806
#[stable(feature = "rust1", since = "1.0.0")]
17611807
impl<'a, T> ExactSizeIterator for Drain<'a, T> {}
1808+
1809+
/// A splicing iterator for `Vec<T>`. See the [`Vec::splice`](struct.Vec.html#method.splice) method.
1810+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1811+
pub struct Splice<'a, I: Iterator + 'a> {
1812+
drain: Drain<'a, I::Item>,
1813+
replace_with: I,
1814+
}
1815+
1816+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1817+
impl<'a, I: Iterator> Iterator for Splice<'a, I> {
1818+
type Item = I::Item;
1819+
1820+
fn next(&mut self) -> Option<Self::Item> {
1821+
self.drain.next()
1822+
}
1823+
1824+
fn size_hint(&self) -> (usize, Option<usize>) {
1825+
self.drain.size_hint()
1826+
}
1827+
}
1828+
1829+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1830+
impl<'a, I: Iterator> DoubleEndedIterator for Splice<'a, I> {
1831+
fn next_back(&mut self) -> Option<Self::Item> {
1832+
self.drain.next_back()
1833+
}
1834+
}
1835+
1836+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1837+
impl<'a, I: Iterator> ExactSizeIterator for Splice<'a, I> {}
1838+
1839+
1840+
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
1841+
impl<'a, I: Iterator> Drop for Splice<'a, I> {
1842+
fn drop(&mut self) {
1843+
// exhaust drain first
1844+
while let Some(_) = self.drain.next() {}
1845+
1846+
1847+
unsafe {
1848+
if self.drain.tail_len == 0 {
1849+
let vec = &mut *self.drain.vec;
1850+
vec.extend(self.replace_with.by_ref());
1851+
return
1852+
}
1853+
1854+
// First fill the range left by drain().
1855+
if !self.drain.fill(&mut self.replace_with) {
1856+
return
1857+
}
1858+
1859+
// There may be more elements. Use the lower bound as an estimate.
1860+
// FIXME: Is the upper bound a better guess? Or something else?
1861+
let (lower_bound, _upper_bound) = self.replace_with.size_hint();
1862+
if lower_bound > 0 {
1863+
self.drain.move_tail(lower_bound);
1864+
if !self.drain.fill(&mut self.replace_with) {
1865+
return
1866+
}
1867+
}
1868+
1869+
// Collect any remaining elements.
1870+
// This is a zero-length vector which does not allocate if `lower_bound` was exact.
1871+
let mut collected = self.replace_with.by_ref().collect::<Vec<I::Item>>().into_iter();
1872+
// Now we have an exact count.
1873+
if collected.len() > 0 {
1874+
self.drain.move_tail(collected.len());
1875+
let filled = self.drain.fill(&mut collected);
1876+
debug_assert!(filled);
1877+
debug_assert_eq!(collected.len(), 0);
1878+
}
1879+
}
1880+
// Let `Drain::drop` move the tail back if necessary and restore `vec.len`.
1881+
}
1882+
}
1883+
1884+
/// Private helper methods for `Splice::drop`
1885+
impl<'a, T> Drain<'a, T> {
1886+
/// The range from `self.vec.len` to `self.tail_start` contains elements
1887+
/// that have been moved out.
1888+
/// Fill that range as much as possible with new elements from the `replace_with` iterator.
1889+
/// Return whether we filled the entire range. (`replace_with.next()` didn’t return `None`.)
1890+
unsafe fn fill<I: Iterator<Item=T>>(&mut self, replace_with: &mut I) -> bool {
1891+
let vec = &mut *self.vec;
1892+
let range_start = vec.len;
1893+
let range_end = self.tail_start;
1894+
let range_slice = slice::from_raw_parts_mut(
1895+
vec.as_mut_ptr().offset(range_start as isize),
1896+
range_end - range_start);
1897+
1898+
for place in range_slice {
1899+
if let Some(new_item) = replace_with.next() {
1900+
ptr::write(place, new_item);
1901+
vec.len += 1;
1902+
} else {
1903+
return false
1904+
}
1905+
}
1906+
true
1907+
}
1908+
1909+
/// Make room for inserting more elements before the tail.
1910+
unsafe fn move_tail(&mut self, extra_capacity: usize) {
1911+
let vec = &mut *self.vec;
1912+
let used_capacity = self.tail_start + self.tail_len;
1913+
vec.buf.reserve(used_capacity, extra_capacity);
1914+
1915+
let new_tail_start = self.tail_start + extra_capacity;
1916+
let src = vec.as_ptr().offset(self.tail_start as isize);
1917+
let dst = vec.as_mut_ptr().offset(new_tail_start as isize);
1918+
ptr::copy(src, dst, self.tail_len);
1919+
self.tail_start = new_tail_start;
1920+
}
1921+
}

src/libcollectionstest/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#![feature(pattern)]
2626
#![feature(rand)]
2727
#![feature(set_recovery)]
28+
#![feature(splice)]
2829
#![feature(step_by)]
2930
#![feature(str_char)]
3031
#![feature(str_escape)]

src/libcollectionstest/string.rs

+8
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,14 @@ fn test_drain() {
373373
assert_eq!(t, "");
374374
}
375375

376+
#[test]
377+
fn test_splice() {
378+
let mut s = "Hello, world!".to_owned();
379+
let t: String = s.splice(7..12, "世界").collect();
380+
assert_eq!(s, "Hello, 世界!");
381+
assert_eq!(t, "world");
382+
}
383+
376384
#[test]
377385
fn test_extend_ref() {
378386
let mut a = "foo".to_string();

src/libcollectionstest/vec.rs

+10
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,16 @@ fn test_drain_range() {
438438
assert_eq!(v, &[(), ()]);
439439
}
440440

441+
#[test]
442+
fn splice() {
443+
let mut v = vec![1, 2, 3, 4, 5];
444+
let a = [10, 11, 12];
445+
v.splice(2..4, a.iter().cloned());
446+
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
447+
v.splice(1..3, Some(20));
448+
assert_eq!(v, &[1, 20, 11, 12, 5]);
449+
}
450+
441451
#[test]
442452
fn test_into_boxed_slice() {
443453
let xs = vec![1, 2, 3];

0 commit comments

Comments
 (0)