Skip to content
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

Implement additional split_inclusive variants for slices #91546

Closed
1 change: 1 addition & 0 deletions library/alloc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@
#![feature(slice_ptr_get)]
#![feature(slice_ptr_len)]
#![feature(slice_range)]
#![feature(split_inclusive_variants)]
#![feature(str_internals)]
#![feature(strict_provenance)]
#![feature(trusted_len)]
Expand Down
7 changes: 7 additions & 0 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ pub use core::slice::{Iter, IterMut};
pub use core::slice::{RChunks, RChunksExact, RChunksExactMut, RChunksMut};
#[stable(feature = "slice_rsplit", since = "1.27.0")]
pub use core::slice::{RSplit, RSplitMut};
#[unstable(feature = "split_inclusive_variants", issue = "none")]
pub use core::slice::{
RSplitInclusive, RSplitInclusiveMut, RSplitLeftInclusive, RSplitLeftInclusiveMut,
RSplitNInclusive, RSplitNInclusiveMut, RSplitNLeftInclusive, RSplitNLeftInclusiveMut,
SplitLeftInclusive, SplitLeftInclusiveMut, SplitNInclusive, SplitNInclusiveMut,
SplitNLeftInclusive, SplitNLeftInclusiveMut,
};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut};
#[stable(feature = "split_inclusive", since = "1.51.0")]
Expand Down
5 changes: 5 additions & 0 deletions library/alloc/src/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ pub use core::str::{MatchIndices, RMatchIndices};
pub use core::str::{Matches, RMatches};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::{RSplit, Split};
#[unstable(feature = "split_inclusive_variants", issue = "none")]
pub use core::str::{
RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, SplitEnds,
SplitInitiator, SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive,
};
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::str::{RSplitN, SplitN};
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
1 change: 1 addition & 0 deletions library/alloc/tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#![feature(bench_black_box)]
#![feature(strict_provenance)]
#![feature(once_cell)]
#![feature(split_inclusive_variants)]

use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
Expand Down
253 changes: 248 additions & 5 deletions library/alloc/tests/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,246 @@ fn test_splitator_mut_inclusive_reverse() {
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}

#[test]
fn test_splitator_left_inclusive() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.split_left_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
}

#[test]
fn test_splitator_left_inclusive_reverse() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.split_left_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}

#[test]
fn test_splitator_left_inclusive_mut() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.split_left_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
}

#[test]
fn test_splitator_left_inclusive_reverse_mut() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.split_left_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_inclusive() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
assert_eq!(xs.rsplit_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.rsplit_inclusive(|_| true).collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_inclusive_reverse() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
assert_eq!(xs.rsplit_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.rsplit_inclusive(|_| true).rev().collect::<Vec<&[i32]>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
}

#[test]
fn test_rsplitator_mut_inclusive() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[5], &[3, 4], &[1, 2]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.rsplit_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_mut_inclusive_reverse() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.rsplit_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_left_inclusive() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.rsplit_left_inclusive(|_| true).collect::<Vec<_>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_left_inclusive_reverse() {
let xs = &[1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.rsplit_left_inclusive(|_| true).rev().collect::<Vec<&[i32]>>(), splits);

let xs: &[i32] = &[];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::<Vec<&[i32]>>(), splits);
}

#[test]
fn test_rsplitator_left_inclusive_mut() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
}

#[test]
fn test_rsplitator_left_inclusive_reverse_mut() {
let xs = &mut [1, 2, 3, 4, 5];

let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);

let xs: &mut [i32] = &mut [];
let splits: &[&[i32]] = &[];
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
}

#[test]
fn test_splitnator() {
let xs = &[1, 2, 3, 4, 5];
Expand Down Expand Up @@ -996,7 +1236,7 @@ fn test_rsplitnator() {

#[test]
fn test_split_iterators_size_hint() {
#[derive(Copy, Clone)]
#[derive(Copy, Clone, PartialEq, Eq)]
enum Bounds {
Lower,
Upper,
Expand Down Expand Up @@ -1027,8 +1267,9 @@ fn test_split_iterators_size_hint() {

// p: predicate, b: bound selection
for (p, b) in [
// with a predicate always returning false, the split*-iterators
// become maximally short, so the size_hint lower bounds are tight
// with a predicate always returning false, the non-inclusive
// split*-iterators become maximally short, so the size_hint
// lower bounds are tight
((|_| false) as fn(&_) -> _, Bounds::Lower),
// with a predicate always returning true, the split*-iterators
// become maximally long, so the size_hint upper bounds are tight
Expand All @@ -1039,8 +1280,10 @@ fn test_split_iterators_size_hint() {

a(v.split(p), b, "split");
a(v.split_mut(p), b, "split_mut");
a(v.split_inclusive(p), b, "split_inclusive");
a(v.split_inclusive_mut(p), b, "split_inclusive_mut");
if b == Bounds::Upper {
a(v.split_inclusive(p), b, "split_inclusive");
a(v.split_inclusive_mut(p), b, "split_inclusive_mut");
}
a(v.rsplit(p), b, "rsplit");
a(v.rsplit_mut(p), b, "rsplit_mut");

Expand Down
57 changes: 57 additions & 0 deletions library/alloc/tests/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1438,6 +1438,63 @@ fn test_split_char_iterator_inclusive_rev() {
assert_eq!(split, ["CaT", "TurtlE", "SharK", "SheeP"]);
}

#[test]
fn test_split_char_iterator_left_inclusive() {
let split: Vec<&str> = "\n\n\n\n".split_left_inclusive('\n').collect();
assert_eq!(split, ["\n", "\n", "\n", "\n"]);

let split: Vec<&str> = "".split_left_inclusive('\n').collect();
let rhs: [&str; 0] = [];
assert_eq!(split, rhs);

let data = "\nMäry häd ä little lämb\nLittle lämb\n";

let split: Vec<&str> = data.split_left_inclusive('\n').collect();
assert_eq!(split, ["\nMäry häd ä little lämb", "\nLittle lämb", "\n"]);

let uppercase_separated = "SheePSharKTurtlECaT";
let mut first_char = true;
let split: Vec<&str> = uppercase_separated
.split_left_inclusive(|c: char| {
let split = !first_char && c.is_uppercase();
first_char = split;
split
})
.collect();
assert_eq!(split, ["Shee", "PShar", "KTurtl", "ECa", "T"]);
}

#[test]
fn test_split_char_iterator_left_inclusive_rev() {
let split: Vec<&str> = "\n\n\n\n".split_left_inclusive('\n').rev().collect();
assert_eq!(split, ["\n", "\n", "\n", "\n"]);

let split: Vec<&str> = "".split_left_inclusive('\n').rev().collect();
let rhs: [&str; 0] = [];
assert_eq!(split, rhs);

let data = "\nMäry häd ä little lämb\nLittle lämb\n";

let split: Vec<&str> = data.split_left_inclusive('\n').rev().collect();
assert_eq!(split, ["\n", "\nLittle lämb", "\nMäry häd ä little lämb"]);

// Note that the predicate is stateful and thus dependent
// on the iteration order.
// (A different predicate is needed for reverse iterator vs normal iterator.)
// Not sure if anything can be done though.
let uppercase_separated = "SheePSharKTurtlECaT";
let mut term_char = true;
let split: Vec<&str> = uppercase_separated
.split_left_inclusive(|c: char| {
let split = term_char && c.is_uppercase();
term_char = c.is_uppercase();
split
})
.rev()
.collect();
assert_eq!(split, ["T", "ECa", "KTurtl", "PShar", "Shee",]);
}

#[test]
fn test_rsplit() {
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
Expand Down
Loading