Skip to content

Rollup of 3 pull requests #41503

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
22 changes: 16 additions & 6 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,11 @@ def build_triple(self):
# The goal here is to come up with the same triple as LLVM would,
# at least for the subset of platforms we're willing to target.
if ostype == 'Linux':
ostype = 'unknown-linux-gnu'
os = subprocess.check_output(['uname', '-o']).strip().decode(default_encoding)
if os == 'Android':
ostype = 'linux-android'
else:
ostype = 'unknown-linux-gnu'
elif ostype == 'FreeBSD':
ostype = 'unknown-freebsd'
elif ostype == 'DragonFly':
Expand Down Expand Up @@ -464,15 +468,21 @@ def build_triple(self):
cputype = 'i686'
elif cputype in {'xscale', 'arm'}:
cputype = 'arm'
if ostype == 'linux-android':
ostype = 'linux-androideabi'
elif cputype == 'armv6l':
cputype = 'arm'
ostype += 'eabihf'
if ostype == 'linux-android':
ostype = 'linux-androideabi'
else:
ostype += 'eabihf'
elif cputype in {'armv7l', 'armv8l'}:
cputype = 'armv7'
ostype += 'eabihf'
elif cputype == 'aarch64':
cputype = 'aarch64'
elif cputype == 'arm64':
if ostype == 'linux-android':
ostype = 'linux-androideabi'
else:
ostype += 'eabihf'
elif cputype in {'aarch64', 'arm64'}:
cputype = 'aarch64'
elif cputype == 'mips':
if sys.byteorder == 'big':
Expand Down
1 change: 1 addition & 0 deletions src/doc/unstable-book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
- [slice_rsplit](library-features/slice-rsplit.md)
- [sort_internals](library-features/sort-internals.md)
- [sort_unstable](library-features/sort-unstable.md)
- [splice](library-features/splice.md)
- [step_by](library-features/step-by.md)
- [step_trait](library-features/step-trait.md)
- [str_checked_slicing](library-features/str-checked-slicing.md)
Expand Down
24 changes: 24 additions & 0 deletions src/doc/unstable-book/src/library-features/splice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# `splice`

The tracking issue for this feature is: [#32310]

[#32310]: https://github.com/rust-lang/rust/issues/32310

------------------------

The `splice()` method on `Vec` and `String` allows you to replace a range
of values in a vector or string with another range of values, and returns
the replaced values.

A simple example:

```rust
#![feature(splice)]
let mut s = String::from("α is alpha, β is beta");
let beta_offset = s.find('β').unwrap_or(s.len());

// Replace the range up until the β from the string
let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
assert_eq!(t, "α is alpha, ");
assert_eq!(s, "Α is capital alpha; β is beta");
```
6 changes: 1 addition & 5 deletions src/libcollections/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1519,13 +1519,9 @@ impl<T: Clone> ToOwned for [T] {
self.to_vec()
}

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

fn clone_into(&self, target: &mut Vec<T>) {
Expand Down
125 changes: 124 additions & 1 deletion src/libcollections/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1316,7 +1316,7 @@ impl String {
self.vec.clear()
}

/// Create a draining iterator that removes the specified range in the string
/// Creates a draining iterator that removes the specified range in the string
/// and yields the removed chars.
///
/// Note: The element range is removed even if the iterator is not
Expand Down Expand Up @@ -1382,6 +1382,71 @@ impl String {
}
}

/// Creates a splicing iterator that removes the specified range in the string,
/// replaces with the given string, and yields the removed chars.
/// The given string doesn’t need to be the same length as the range.
///
/// Note: The element range is removed when the `Splice` is dropped,
/// even if the iterator is not consumed until the end.
///
/// # Panics
///
/// Panics if the starting point or end point do not lie on a [`char`]
/// boundary, or if they're out of bounds.
///
/// [`char`]: ../../std/primitive.char.html
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(splice)]
/// let mut s = String::from("α is alpha, β is beta");
/// let beta_offset = s.find('β').unwrap_or(s.len());
///
/// // Replace the range up until the β from the string
/// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
/// assert_eq!(t, "α is alpha, ");
/// assert_eq!(s, "Α is capital alpha; β is beta");
/// ```
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b>
where R: RangeArgument<usize>
{
// Memory safety
//
// The String version of Splice does not have the memory safety issues
// of the vector version. The data is just plain bytes.
// Because the range removal happens in Drop, if the Splice iterator is leaked,
// the removal will not happen.
let len = self.len();
let start = match range.start() {
Included(&n) => n,
Excluded(&n) => n + 1,
Unbounded => 0,
};
let end = match range.end() {
Included(&n) => n + 1,
Excluded(&n) => n,
Unbounded => len,
};

// Take out two simultaneous borrows. The &mut String won't be accessed
// until iteration is over, in Drop.
let self_ptr = self as *mut _;
// slicing does the appropriate bounds checks
let chars_iter = self[start..end].chars();

Splice {
start: start,
end: end,
iter: chars_iter,
string: self_ptr,
replace_with: replace_with
}
}

/// Converts this `String` into a `Box<str>`.
///
/// This will drop any excess capacity.
Expand Down Expand Up @@ -2145,3 +2210,61 @@ impl<'a> DoubleEndedIterator for Drain<'a> {

#[unstable(feature = "fused", issue = "35602")]
impl<'a> FusedIterator for Drain<'a> {}

/// A splicing iterator for `String`.
///
/// This struct is created by the [`splice()`] method on [`String`]. See its
/// documentation for more.
///
/// [`splice()`]: struct.String.html#method.splice
/// [`String`]: struct.String.html
#[derive(Debug)]
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub struct Splice<'a, 'b> {
/// Will be used as &'a mut String in the destructor
string: *mut String,
/// Start of part to remove
start: usize,
/// End of part to remove
end: usize,
/// Current remaining range to remove
iter: Chars<'a>,
replace_with: &'b str,
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Drop for Splice<'a, 'b> {
fn drop(&mut self) {
unsafe {
let vec = (*self.string).as_mut_vec();
vec.splice(self.start..self.end, self.replace_with.bytes());
}
}
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Iterator for Splice<'a, 'b> {
type Item = char;

#[inline]
fn next(&mut self) -> Option<char> {
self.iter.next()
}

fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
#[inline]
fn next_back(&mut self) -> Option<char> {
self.iter.next_back()
}
}
1 change: 1 addition & 0 deletions src/libcollections/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#![feature(pattern)]
#![feature(placement_in_syntax)]
#![feature(rand)]
#![feature(splice)]
#![feature(step_by)]
#![feature(str_escape)]
#![feature(test)]
Expand Down
56 changes: 56 additions & 0 deletions src/libcollections/tests/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,62 @@ fn test_drain() {
assert_eq!(t, "");
}

#[test]
fn test_splice() {
let mut s = "Hello, world!".to_owned();
let t: String = s.splice(7..12, "世界").collect();
assert_eq!(s, "Hello, 世界!");
assert_eq!(t, "world");
}

#[test]
#[should_panic]
fn test_splice_char_boundary() {
let mut s = "Hello, 世界!".to_owned();
s.splice(..8, "");
}

#[test]
fn test_splice_inclusive_range() {
let mut v = String::from("12345");
let t: String = v.splice(2...3, "789").collect();
assert_eq!(v, "127895");
assert_eq!(t, "34");
let t2: String = v.splice(1...2, "A").collect();
assert_eq!(v, "1A895");
assert_eq!(t2, "27");
}

#[test]
#[should_panic]
fn test_splice_out_of_bounds() {
let mut s = String::from("12345");
s.splice(5..6, "789");
}

#[test]
#[should_panic]
fn test_splice_inclusive_out_of_bounds() {
let mut s = String::from("12345");
s.splice(5...5, "789");
}

#[test]
fn test_splice_empty() {
let mut s = String::from("12345");
let t: String = s.splice(1..2, "").collect();
assert_eq!(s, "1345");
assert_eq!(t, "2");
}

#[test]
fn test_splice_unbounded() {
let mut s = String::from("12345");
let t: String = s.splice(.., "").collect();
assert_eq!(s, "");
assert_eq!(t, "12345");
}

#[test]
fn test_extend_ref() {
let mut a = "foo".to_string();
Expand Down
55 changes: 55 additions & 0 deletions src/libcollections/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,61 @@ fn test_drain_inclusive_out_of_bounds() {
v.drain(5...5);
}

#[test]
fn test_splice() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
v.splice(2..4, a.iter().cloned());
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
v.splice(1..3, Some(20));
assert_eq!(v, &[1, 20, 11, 12, 5]);
}

#[test]
fn test_splice_inclusive_range() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
let t1: Vec<_> = v.splice(2...3, a.iter().cloned()).collect();
assert_eq!(v, &[1, 2, 10, 11, 12, 5]);
assert_eq!(t1, &[3, 4]);
let t2: Vec<_> = v.splice(1...2, Some(20)).collect();
assert_eq!(v, &[1, 20, 11, 12, 5]);
assert_eq!(t2, &[2, 10]);
}

#[test]
#[should_panic]
fn test_splice_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
v.splice(5..6, a.iter().cloned());
}

#[test]
#[should_panic]
fn test_splice_inclusive_out_of_bounds() {
let mut v = vec![1, 2, 3, 4, 5];
let a = [10, 11, 12];
v.splice(5...5, a.iter().cloned());
}

#[test]
fn test_splice_items_zero_sized() {
let mut vec = vec![(), (), ()];
let vec2 = vec![];
let t: Vec<_> = vec.splice(1..2, vec2.iter().cloned()).collect();
assert_eq!(vec, &[(), ()]);
assert_eq!(t, &[()]);
}

#[test]
fn test_splice_unbounded() {
let mut vec = vec![1, 2, 3, 4, 5];
let t: Vec<_> = vec.splice(.., None).collect();
assert_eq!(vec, &[]);
assert_eq!(t, &[1, 2, 3, 4, 5]);
}

#[test]
fn test_into_boxed_slice() {
let xs = vec![1, 2, 3];
Expand Down
Loading