Skip to content

Commit 86bf962

Browse files
committed
Implement split_inclusive for slice and str, an splitting iterator that includes the matched part in the iterated substrings as a terminator.
1 parent 8647aa1 commit 86bf962

File tree

5 files changed

+422
-1
lines changed

5 files changed

+422
-1
lines changed

src/liballoc/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#![feature(binary_heap_into_iter_sorted)]
1313
#![feature(binary_heap_drain_sorted)]
1414
#![feature(vec_remove_item)]
15+
#![feature(split_inclusive)]
1516

1617
use std::collections::hash_map::DefaultHasher;
1718
use std::hash::{Hash, Hasher};

src/liballoc/tests/slice.rs

+20
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,26 @@ fn test_splitator() {
851851
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
852852
}
853853

854+
#[test]
855+
fn test_splitator_inclusive() {
856+
let xs = &[1, 2, 3, 4, 5];
857+
858+
let splits: &[&[_]] = &[&[1, 2], &[3, 4], &[5]];
859+
assert_eq!(xs.split_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
860+
let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]];
861+
assert_eq!(xs.split_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
862+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5], &[]];
863+
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
864+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
865+
assert_eq!(xs.split_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
866+
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5], &[]];
867+
assert_eq!(xs.split_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
868+
869+
let xs: &[i32] = &[];
870+
let splits: &[&[i32]] = &[&[]];
871+
assert_eq!(xs.split_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
872+
}
873+
854874
#[test]
855875
fn test_splitnator() {
856876
let xs = &[1, 2, 3, 4, 5];

src/liballoc/tests/str.rs

+18
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,24 @@ fn test_split_char_iterator_no_trailing() {
12471247
assert_eq!(split, ["", "Märy häd ä little lämb", "Little lämb"]);
12481248
}
12491249

1250+
#[test]
1251+
fn test_split_char_iterator_inclusive() {
1252+
let data = "\nMäry häd ä little lämb\nLittle lämb\n";
1253+
1254+
let split: Vec<&str> = data.split_inclusive('\n').collect();
1255+
assert_eq!(split, ["\n", "Märy häd ä little lämb\n", "Little lämb\n", ""]);
1256+
1257+
let uppercase_separated = "SheePSharKTurtlECaT";
1258+
let mut first_char = true;
1259+
let split: Vec<&str> = uppercase_separated.split_inclusive(|c: char| {
1260+
let split = !first_char && c.is_uppercase();
1261+
first_char = split;
1262+
split
1263+
}).collect();
1264+
assert_eq!(split, ["SheeP", "SharK", "TurtlE", "CaT", ""]);
1265+
}
1266+
1267+
12501268
#[test]
12511269
fn test_rsplit() {
12521270
let data = "\nMäry häd ä little lämb\nLittle lämb\n";

src/libcore/slice/mod.rs

+260-1
Original file line numberDiff line numberDiff line change
@@ -1155,6 +1155,72 @@ impl<T> [T] {
11551155
SplitMut { v: self, pred, finished: false }
11561156
}
11571157

1158+
/// Returns an iterator over subslices separated by elements that match
1159+
/// `pred`. The matched element is contained in the end of the previous
1160+
/// subslice as a terminator.
1161+
///
1162+
/// # Examples
1163+
///
1164+
/// ```
1165+
/// #![feature(split_inclusive)]
1166+
/// let slice = [10, 40, 33, 20];
1167+
/// let mut iter = slice.split_inclusive(|num| num % 3 == 0);
1168+
///
1169+
/// assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
1170+
/// assert_eq!(iter.next().unwrap(), &[20]);
1171+
/// assert!(iter.next().is_none());
1172+
/// ```
1173+
///
1174+
/// If the first element is matched, an empty slice will be the first item
1175+
/// returned by the iterator. Similarly, if the last element in the slice
1176+
/// is matched, an empty slice will be the last item returned by the
1177+
/// iterator:
1178+
///
1179+
/// ```
1180+
/// #![feature(split_inclusive)]
1181+
/// let slice = [10, 40, 33];
1182+
/// let mut iter = slice.split_inclusive(|num| num % 3 == 0);
1183+
///
1184+
/// assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
1185+
/// assert_eq!(iter.next().unwrap(), &[]);
1186+
/// assert!(iter.next().is_none());
1187+
/// ```
1188+
#[unstable(feature = "split_inclusive", issue = "0")]
1189+
#[inline]
1190+
pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F>
1191+
where F: FnMut(&T) -> bool
1192+
{
1193+
SplitInclusive {
1194+
v: self,
1195+
pred,
1196+
finished: false
1197+
}
1198+
}
1199+
1200+
/// Returns an iterator over mutable subslices separated by elements that
1201+
/// match `pred`. The matched element is contained in the previous
1202+
/// subslice as a terminator.
1203+
///
1204+
/// # Examples
1205+
///
1206+
/// ```
1207+
/// #![feature(split_inclusive)]
1208+
/// let mut v = [10, 40, 30, 20, 60, 50];
1209+
///
1210+
/// for group in v.split_inclusive_mut(|num| *num % 3 == 0) {
1211+
/// let terminator_idx = group.len()-1;
1212+
/// group[terminator_idx] = 1;
1213+
/// }
1214+
/// assert_eq!(v, [10, 40, 1, 20, 1, 1]);
1215+
/// ```
1216+
#[unstable(feature = "split_inclusive", issue = "0")]
1217+
#[inline]
1218+
pub fn split_inclusive_mut<F>(&mut self, pred: F) -> SplitInclusiveMut<'_, T, F>
1219+
where F: FnMut(&T) -> bool
1220+
{
1221+
SplitInclusiveMut { v: self, pred, finished: false }
1222+
}
1223+
11581224
/// Returns an iterator over subslices separated by elements that match
11591225
/// `pred`, starting at the end of the slice and working backwards.
11601226
/// The matched element is not contained in the subslices.
@@ -3675,7 +3741,100 @@ where
36753741
#[stable(feature = "fused", since = "1.26.0")]
36763742
impl<T, P> FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {}
36773743

3678-
/// An iterator over the subslices of the vector which are separated
3744+
/// An iterator over subslices separated by elements that match a predicate
3745+
/// function. Unlike `Split`, it contains the matched part as a terminator
3746+
/// of the subslice.
3747+
///
3748+
/// This struct is created by the [`split_inclusive`] method on [slices].
3749+
///
3750+
/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive
3751+
/// [slices]: ../../std/primitive.slice.html
3752+
#[unstable(feature = "split_inclusive", issue = "0")]
3753+
pub struct SplitInclusive<'a, T:'a, P> where P: FnMut(&T) -> bool {
3754+
v: &'a [T],
3755+
pred: P,
3756+
finished: bool
3757+
}
3758+
3759+
#[unstable(feature = "split_inclusive", issue = "0")]
3760+
impl<T: fmt::Debug, P> fmt::Debug for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {
3761+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3762+
f.debug_struct("SplitInclusive")
3763+
.field("v", &self.v)
3764+
.field("finished", &self.finished)
3765+
.finish()
3766+
}
3767+
}
3768+
3769+
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
3770+
#[unstable(feature = "split_inclusive", issue = "0")]
3771+
impl<T, P> Clone for SplitInclusive<'_, T, P> where P: Clone + FnMut(&T) -> bool {
3772+
fn clone(&self) -> Self {
3773+
SplitInclusive {
3774+
v: self.v,
3775+
pred: self.pred.clone(),
3776+
finished: self.finished,
3777+
}
3778+
}
3779+
}
3780+
3781+
#[unstable(feature = "split_inclusive", issue = "0")]
3782+
impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
3783+
type Item = &'a [T];
3784+
3785+
#[inline]
3786+
fn next(&mut self) -> Option<&'a [T]> {
3787+
if self.finished { return None; }
3788+
3789+
match self.v.iter().position(|x| (self.pred)(x)) {
3790+
None => self.finish(),
3791+
Some(idx) => {
3792+
let ret = Some(&self.v[..idx + 1]);
3793+
self.v = &self.v[idx + 1..];
3794+
ret
3795+
}
3796+
}
3797+
}
3798+
3799+
#[inline]
3800+
fn size_hint(&self) -> (usize, Option<usize>) {
3801+
if self.finished {
3802+
(0, Some(0))
3803+
} else {
3804+
(1, Some(self.v.len() + 1))
3805+
}
3806+
}
3807+
}
3808+
3809+
#[unstable(feature = "split_inclusive", issue = "0")]
3810+
impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
3811+
#[inline]
3812+
fn next_back(&mut self) -> Option<&'a [T]> {
3813+
if self.finished { return None; }
3814+
3815+
match self.v.iter().rposition(|x| (self.pred)(x)) {
3816+
None => self.finish(),
3817+
Some(idx) => {
3818+
let ret = Some(&self.v[idx + 1..]);
3819+
self.v = &self.v[..idx];
3820+
ret
3821+
}
3822+
}
3823+
}
3824+
}
3825+
3826+
#[unstable(feature = "split_inclusive", issue = "0")]
3827+
impl<'a, T, P> SplitIter for SplitInclusive<'a, T, P> where P: FnMut(&T) -> bool {
3828+
#[inline]
3829+
fn finish(&mut self) -> Option<&'a [T]> {
3830+
if self.finished { None } else { self.finished = true; Some(self.v) }
3831+
}
3832+
}
3833+
3834+
#[unstable(feature = "split_inclusive", issue = "0")]
3835+
impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
3836+
3837+
/// An iterator over the mutable subslices of the vector which are separated
36793838
/// by elements that match `pred`.
36803839
///
36813840
/// This struct is created by the [`split_mut`] method on [slices].
@@ -3789,6 +3948,106 @@ where
37893948
#[stable(feature = "fused", since = "1.26.0")]
37903949
impl<T, P> FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {}
37913950

3951+
/// An iterator over the mutable subslices of the vector which are separated
3952+
/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
3953+
/// parts in the ends of the subslices.
3954+
///
3955+
/// This struct is created by the [`split_inclusive_mut`] method on [slices].
3956+
///
3957+
/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut
3958+
/// [slices]: ../../std/primitive.slice.html
3959+
#[unstable(feature = "split_inclusive", issue = "0")]
3960+
pub struct SplitInclusiveMut<'a, T:'a, P> where P: FnMut(&T) -> bool {
3961+
v: &'a mut [T],
3962+
pred: P,
3963+
finished: bool
3964+
}
3965+
3966+
#[unstable(feature = "split_inclusive", issue = "0")]
3967+
impl<T: fmt::Debug, P> fmt::Debug for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {
3968+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3969+
f.debug_struct("SplitInclusiveMut")
3970+
.field("v", &self.v)
3971+
.field("finished", &self.finished)
3972+
.finish()
3973+
}
3974+
}
3975+
3976+
#[unstable(feature = "split_inclusive", issue = "0")]
3977+
impl<'a, T, P> SplitIter for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool {
3978+
#[inline]
3979+
fn finish(&mut self) -> Option<&'a mut [T]> {
3980+
if self.finished {
3981+
None
3982+
} else {
3983+
self.finished = true;
3984+
Some(mem::replace(&mut self.v, &mut []))
3985+
}
3986+
}
3987+
}
3988+
3989+
#[unstable(feature = "split_inclusive", issue = "0")]
3990+
impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool {
3991+
type Item = &'a mut [T];
3992+
3993+
#[inline]
3994+
fn next(&mut self) -> Option<&'a mut [T]> {
3995+
if self.finished { return None; }
3996+
3997+
let idx_opt = { // work around borrowck limitations
3998+
let pred = &mut self.pred;
3999+
self.v.iter().position(|x| (*pred)(x))
4000+
};
4001+
match idx_opt {
4002+
None => self.finish(),
4003+
Some(idx) => {
4004+
let tmp = mem::replace(&mut self.v, &mut []);
4005+
let (head, tail) = tmp.split_at_mut(idx+1);
4006+
self.v = tail;
4007+
Some(head)
4008+
}
4009+
}
4010+
}
4011+
4012+
#[inline]
4013+
fn size_hint(&self) -> (usize, Option<usize>) {
4014+
if self.finished {
4015+
(0, Some(0))
4016+
} else {
4017+
// if the predicate doesn't match anything, we yield one slice
4018+
// if it matches every element, we yield len+1 empty slices.
4019+
(1, Some(self.v.len() + 1))
4020+
}
4021+
}
4022+
}
4023+
4024+
#[unstable(feature = "split_inclusive", issue = "0")]
4025+
impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> where
4026+
P: FnMut(&T) -> bool,
4027+
{
4028+
#[inline]
4029+
fn next_back(&mut self) -> Option<&'a mut [T]> {
4030+
if self.finished { return None; }
4031+
4032+
let idx_opt = { // work around borrowck limitations
4033+
let pred = &mut self.pred;
4034+
self.v.iter().rposition(|x| (*pred)(x))
4035+
};
4036+
match idx_opt {
4037+
None => self.finish(),
4038+
Some(idx) => {
4039+
let tmp = mem::replace(&mut self.v, &mut []);
4040+
let (head, tail) = tmp.split_at_mut(idx+1);
4041+
self.v = head;
4042+
Some(tail)
4043+
}
4044+
}
4045+
}
4046+
}
4047+
4048+
#[unstable(feature = "split_inclusive", issue = "0")]
4049+
impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
4050+
37924051
/// An iterator over subslices separated by elements that match a predicate
37934052
/// function, starting from the end of the slice.
37944053
///

0 commit comments

Comments
 (0)