Skip to content

Commit 176be5f

Browse files
Jules BertholetJules-Bertholet
authored andcommitted
Implement split_left_inclusive for slices
1 parent 967a9c9 commit 176be5f

File tree

6 files changed

+402
-0
lines changed

6 files changed

+402
-0
lines changed

library/alloc/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@
133133
#![feature(slice_ptr_get)]
134134
#![feature(slice_ptr_len)]
135135
#![feature(slice_range)]
136+
#![feature(split_left_inclusive)]
136137
#![feature(str_internals)]
137138
#![feature(strict_provenance)]
138139
#![feature(trusted_len)]

library/alloc/src/slice.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,8 @@ pub use core::slice::{RSplit, RSplitMut};
136136
pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut};
137137
#[stable(feature = "split_inclusive", since = "1.51.0")]
138138
pub use core::slice::{SplitInclusive, SplitInclusiveMut};
139+
#[unstable(feature = "split_left_inclusive", issue = "none")]
140+
pub use core::slice::{SplitLeftInclusive, SplitLeftInclusiveMut};
139141

140142
////////////////////////////////////////////////////////////////////////////////
141143
// Basic slice extension methods

library/alloc/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#![feature(bench_black_box)]
4343
#![feature(strict_provenance)]
4444
#![feature(once_cell)]
45+
#![feature(split_left_inclusive)]
4546

4647
use std::collections::hash_map::DefaultHasher;
4748
use std::hash::{Hash, Hasher};

library/alloc/tests/slice.rs

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,86 @@ fn test_splitator_mut_inclusive_reverse() {
927927
assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
928928
}
929929

930+
#[test]
931+
fn test_splitator_left_inclusive() {
932+
let xs = &[1, 2, 3, 4, 5];
933+
934+
let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
935+
assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
936+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
937+
assert_eq!(xs.split_left_inclusive(|x| *x == 1).collect::<Vec<_>>(), splits);
938+
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
939+
assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::<Vec<_>>(), splits);
940+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
941+
assert_eq!(xs.split_left_inclusive(|x| *x == 10).collect::<Vec<_>>(), splits);
942+
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
943+
assert_eq!(xs.split_left_inclusive(|_| true).collect::<Vec<&[i32]>>(), splits);
944+
945+
let xs: &[i32] = &[];
946+
let splits: &[&[i32]] = &[&[]];
947+
assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::<Vec<&[i32]>>(), splits);
948+
}
949+
950+
#[test]
951+
fn test_splitator_left_inclusive_reverse() {
952+
let xs = &[1, 2, 3, 4, 5];
953+
954+
let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
955+
assert_eq!(xs.split_left_inclusive(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
956+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
957+
assert_eq!(xs.split_left_inclusive(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
958+
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
959+
assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
960+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
961+
assert_eq!(xs.split_left_inclusive(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
962+
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
963+
assert_eq!(xs.split_left_inclusive(|_| true).rev().collect::<Vec<_>>(), splits);
964+
965+
let xs: &[i32] = &[];
966+
let splits: &[&[i32]] = &[&[]];
967+
assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
968+
}
969+
970+
#[test]
971+
fn test_splitator_left_inclusive_mut() {
972+
let xs = &mut [1, 2, 3, 4, 5];
973+
974+
let splits: &[&[_]] = &[&[1], &[2, 3], &[4, 5]];
975+
assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).collect::<Vec<_>>(), splits);
976+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
977+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).collect::<Vec<_>>(), splits);
978+
let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]];
979+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
980+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
981+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).collect::<Vec<_>>(), splits);
982+
let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]];
983+
assert_eq!(xs.split_left_inclusive_mut(|_| true).collect::<Vec<_>>(), splits);
984+
985+
let xs: &mut [i32] = &mut [];
986+
let splits: &[&[i32]] = &[&[]];
987+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::<Vec<_>>(), splits);
988+
}
989+
990+
#[test]
991+
fn test_splitator_left_inclusive_reverse_mut() {
992+
let xs = &mut [1, 2, 3, 4, 5];
993+
994+
let splits: &[&[_]] = &[&[4, 5], &[2, 3], &[1]];
995+
assert_eq!(xs.split_left_inclusive_mut(|x| *x % 2 == 0).rev().collect::<Vec<_>>(), splits);
996+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
997+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).rev().collect::<Vec<_>>(), splits);
998+
let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]];
999+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
1000+
let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]];
1001+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).rev().collect::<Vec<_>>(), splits);
1002+
let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]];
1003+
assert_eq!(xs.split_left_inclusive_mut(|_| true).rev().collect::<Vec<_>>(), splits);
1004+
1005+
let xs: &mut [i32] = &mut [];
1006+
let splits: &[&[i32]] = &[&[]];
1007+
assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::<Vec<_>>(), splits);
1008+
}
1009+
9301010
#[test]
9311011
fn test_splitnator() {
9321012
let xs = &[1, 2, 3, 4, 5];

library/core/src/slice/iter.rs

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,6 +640,129 @@ where
640640
#[stable(feature = "split_inclusive", since = "1.51.0")]
641641
impl<T, P> FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
642642

643+
/// An iterator over subslices separated by elements that match a predicate
644+
/// function. Unlike `Split`, it contains the matched part as an initiator
645+
/// of the subslice.
646+
///
647+
/// This struct is created by the [`split_left_inclusive`] method on [slices].
648+
///
649+
/// # Example
650+
///
651+
/// ```
652+
/// #![feature(split_left_inclusive)]
653+
///
654+
/// let slice = [10, 40, 33, 20];
655+
/// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0);
656+
/// ```
657+
///
658+
/// [`split_left_inclusive`]: slice::split_left_inclusive
659+
/// [slices]: slice
660+
#[unstable(feature = "split_left_inclusive", issue = "none")]
661+
pub struct SplitLeftInclusive<'a, T: 'a, P>
662+
where
663+
P: FnMut(&T) -> bool,
664+
{
665+
v: &'a [T],
666+
pred: P,
667+
finished: bool,
668+
}
669+
670+
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusive<'a, T, P> {
671+
#[inline]
672+
pub(super) fn new(slice: &'a [T], pred: P) -> Self {
673+
Self { v: slice, pred, finished: false }
674+
}
675+
}
676+
677+
#[unstable(feature = "split_left_inclusive", issue = "none")]
678+
impl<T: fmt::Debug, P> fmt::Debug for SplitLeftInclusive<'_, T, P>
679+
where
680+
P: FnMut(&T) -> bool,
681+
{
682+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683+
f.debug_struct("SplitLeftInclusive")
684+
.field("v", &self.v)
685+
.field("finished", &self.finished)
686+
.finish()
687+
}
688+
}
689+
690+
// FIXME(#26925) Remove in favor of `#[derive(Clone)]`
691+
#[unstable(feature = "split_left_inclusive", issue = "none")]
692+
impl<T, P> Clone for SplitLeftInclusive<'_, T, P>
693+
where
694+
P: Clone + FnMut(&T) -> bool,
695+
{
696+
fn clone(&self) -> Self {
697+
SplitLeftInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished }
698+
}
699+
}
700+
701+
#[unstable(feature = "split_left_inclusive", issue = "none")]
702+
impl<'a, T, P> Iterator for SplitLeftInclusive<'a, T, P>
703+
where
704+
P: FnMut(&T) -> bool,
705+
{
706+
type Item = &'a [T];
707+
708+
#[inline]
709+
fn next(&mut self) -> Option<&'a [T]> {
710+
if self.finished {
711+
return None;
712+
}
713+
714+
// The first index of self.v is already checked and found to match
715+
// by the last iteration, so we start searching a new match
716+
// one index to the right.
717+
let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] };
718+
let idx =
719+
remainder.iter().position(|x| (self.pred)(x)).map(|x| x + 1).unwrap_or(self.v.len());
720+
if idx == self.v.len() {
721+
self.finished = true;
722+
}
723+
724+
let ret = Some(&self.v[..idx]);
725+
self.v = &self.v[idx..];
726+
ret
727+
}
728+
729+
#[inline]
730+
fn size_hint(&self) -> (usize, Option<usize>) {
731+
if self.finished {
732+
(0, Some(0))
733+
} else {
734+
// If the predicate doesn't match anything, we yield one slice.
735+
// If it matches every element, we yield `len()` one-element slices,
736+
// or a single empty slice.
737+
(1, Some(cmp::max(1, self.v.len())))
738+
}
739+
}
740+
}
741+
742+
#[unstable(feature = "split_left_inclusive", issue = "none")]
743+
impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusive<'a, T, P>
744+
where
745+
P: FnMut(&T) -> bool,
746+
{
747+
#[inline]
748+
fn next_back(&mut self) -> Option<&'a [T]> {
749+
if self.finished {
750+
return None;
751+
}
752+
753+
let idx = self.v.iter().rposition(|x| (self.pred)(x)).unwrap_or(0);
754+
if idx == 0 {
755+
self.finished = true;
756+
}
757+
let ret = Some(&self.v[idx..]);
758+
self.v = &self.v[..idx];
759+
ret
760+
}
761+
}
762+
763+
#[unstable(feature = "split_left_inclusive", issue = "none")]
764+
impl<T, P> FusedIterator for SplitLeftInclusive<'_, T, P> where P: FnMut(&T) -> bool {}
765+
643766
/// An iterator over the mutable subslices of the vector which are separated
644767
/// by elements that match `pred`.
645768
///
@@ -894,6 +1017,133 @@ where
8941017
#[stable(feature = "split_inclusive", since = "1.51.0")]
8951018
impl<T, P> FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
8961019

1020+
/// An iterator over the mutable subslices of the vector which are separated
1021+
/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched
1022+
/// parts in the beginnings of the subslices.
1023+
///
1024+
/// This struct is created by the [`split_left_inclusive_mut`] method on
1025+
/// [slices].
1026+
///
1027+
/// # Example
1028+
///
1029+
/// ```
1030+
/// #![feature(split_left_inclusive)]
1031+
///
1032+
/// let mut v = [10, 40, 30, 20, 60, 50];
1033+
/// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0);
1034+
/// ```
1035+
///
1036+
/// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut
1037+
/// [slices]: slice
1038+
#[unstable(feature = "split_left_inclusive", issue = "none")]
1039+
pub struct SplitLeftInclusiveMut<'a, T: 'a, P>
1040+
where
1041+
P: FnMut(&T) -> bool,
1042+
{
1043+
v: &'a mut [T],
1044+
pred: P,
1045+
finished: bool,
1046+
}
1047+
1048+
impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusiveMut<'a, T, P> {
1049+
#[inline]
1050+
pub(super) fn new(slice: &'a mut [T], pred: P) -> Self {
1051+
Self { v: slice, pred, finished: false }
1052+
}
1053+
}
1054+
1055+
#[unstable(feature = "split_left_inclusive", issue = "none")]
1056+
impl<T: fmt::Debug, P> fmt::Debug for SplitLeftInclusiveMut<'_, T, P>
1057+
where
1058+
P: FnMut(&T) -> bool,
1059+
{
1060+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1061+
f.debug_struct("SplitLeftInclusiveMut")
1062+
.field("v", &self.v)
1063+
.field("finished", &self.finished)
1064+
.finish()
1065+
}
1066+
}
1067+
1068+
#[unstable(feature = "split_left_inclusive", issue = "none")]
1069+
impl<'a, T, P> Iterator for SplitLeftInclusiveMut<'a, T, P>
1070+
where
1071+
P: FnMut(&T) -> bool,
1072+
{
1073+
type Item = &'a mut [T];
1074+
1075+
#[inline]
1076+
fn next(&mut self) -> Option<&'a mut [T]> {
1077+
if self.finished {
1078+
return None;
1079+
}
1080+
1081+
let idx_opt = {
1082+
// work around borrowck limitations
1083+
let pred = &mut self.pred;
1084+
1085+
// The first index of self.v is already checked and found to match
1086+
// by the last iteration, so we start searching a new match
1087+
// one index to the right.
1088+
let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] };
1089+
remainder.iter().position(|x| (*pred)(x)).map(|x| x + 1)
1090+
};
1091+
let idx = idx_opt.unwrap_or(self.v.len());
1092+
if idx == self.v.len() {
1093+
self.finished = true;
1094+
}
1095+
let tmp = mem::replace(&mut self.v, &mut []);
1096+
let (head, tail) = tmp.split_at_mut(idx);
1097+
self.v = tail;
1098+
Some(head)
1099+
}
1100+
1101+
#[inline]
1102+
fn size_hint(&self) -> (usize, Option<usize>) {
1103+
if self.finished {
1104+
(0, Some(0))
1105+
} else {
1106+
// If the predicate doesn't match anything, we yield one slice.
1107+
// If it matches every element, we yield `len()` one-element slices,
1108+
// or a single empty slice.
1109+
(1, Some(cmp::max(1, self.v.len())))
1110+
}
1111+
}
1112+
}
1113+
1114+
#[unstable(feature = "split_left_inclusive", issue = "none")]
1115+
impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusiveMut<'a, T, P>
1116+
where
1117+
P: FnMut(&T) -> bool,
1118+
{
1119+
#[inline]
1120+
fn next_back(&mut self) -> Option<&'a mut [T]> {
1121+
if self.finished {
1122+
return None;
1123+
}
1124+
1125+
let idx_opt = if self.v.is_empty() {
1126+
None
1127+
} else {
1128+
// work around borrowsck limitations
1129+
let pred = &mut self.pred;
1130+
1131+
self.v.iter().rposition(|x| (*pred)(x))
1132+
};
1133+
let idx = idx_opt.unwrap_or(0);
1134+
if idx == 0 {
1135+
self.finished = true;
1136+
}
1137+
let tmp = mem::replace(&mut self.v, &mut []);
1138+
let (head, tail) = tmp.split_at_mut(idx);
1139+
self.v = head;
1140+
Some(tail)
1141+
}
1142+
}
1143+
1144+
#[unstable(feature = "split_left_inclusive", issue = "none")]
1145+
impl<T, P> FusedIterator for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {}
1146+
8971147
/// An iterator over subslices separated by elements that match a predicate
8981148
/// function, starting from the end of the slice.
8991149
///

0 commit comments

Comments
 (0)