From 176be5f5e6654285684c40fadf204b4f66411432 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 5 Dec 2021 04:44:31 -0500 Subject: [PATCH 01/10] Implement `split_left_inclusive` for slices --- library/alloc/src/lib.rs | 1 + library/alloc/src/slice.rs | 2 + library/alloc/tests/lib.rs | 1 + library/alloc/tests/slice.rs | 80 +++++++++++ library/core/src/slice/iter.rs | 250 +++++++++++++++++++++++++++++++++ library/core/src/slice/mod.rs | 68 +++++++++ 6 files changed, 402 insertions(+) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 315469387e5ae..3b770f5cf382b 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -133,6 +133,7 @@ #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] +#![feature(split_left_inclusive)] #![feature(str_internals)] #![feature(strict_provenance)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 63d4d94529008..64d92f7cbb77f 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -136,6 +136,8 @@ pub use core::slice::{RSplit, RSplitMut}; pub use core::slice::{RSplitN, RSplitNMut, SplitN, SplitNMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use core::slice::{SplitInclusive, SplitInclusiveMut}; +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub use core::slice::{SplitLeftInclusive, SplitLeftInclusiveMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index c29e7b9c81efb..084aadc55170f 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -42,6 +42,7 @@ #![feature(bench_black_box)] #![feature(strict_provenance)] #![feature(once_cell)] +#![feature(split_left_inclusive)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 21f894343be09..2f35568f24e8d 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -927,6 +927,86 @@ fn test_splitator_mut_inclusive_reverse() { assert_eq!(xs.split_inclusive_mut(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_left_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_left_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.split_left_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.split_left_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + #[test] fn test_splitnator() { let xs = &[1, 2, 3, 4, 5]; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 35d00b9dda663..7f480905b0d7b 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -640,6 +640,129 @@ where #[stable(feature = "split_inclusive", since = "1.51.0")] impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} +/// An iterator over subslices separated by elements that match a predicate +/// function. Unlike `Split`, it contains the matched part as an initiator +/// of the subslice. +/// +/// This struct is created by the [`split_left_inclusive`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_left_inclusive)] +/// +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); +/// ``` +/// +/// [`split_left_inclusive`]: slice::split_left_inclusive +/// [slices]: slice +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub struct SplitLeftInclusive<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusive<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl fmt::Debug for SplitLeftInclusive<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitLeftInclusive") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl Clone for SplitLeftInclusive<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + SplitLeftInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, T, P> Iterator for SplitLeftInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + // The first index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the right. + let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] }; + let idx = + remainder.iter().position(|x| (self.pred)(x)).map(|x| x + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx..]; + ret + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len()` one-element slices, + // or a single empty slice. + (1, Some(cmp::max(1, self.v.len()))) + } + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + let idx = self.v.iter().rposition(|x| (self.pred)(x)).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let ret = Some(&self.v[idx..]); + self.v = &self.v[..idx]; + ret + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl FusedIterator for SplitLeftInclusive<'_, T, P> where P: FnMut(&T) -> bool {} + /// An iterator over the mutable subslices of the vector which are separated /// by elements that match `pred`. /// @@ -894,6 +1017,133 @@ where #[stable(feature = "split_inclusive", since = "1.51.0")] impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched +/// parts in the beginnings of the subslices. +/// +/// This struct is created by the [`split_left_inclusive_mut`] method on +/// [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_left_inclusive)] +/// +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0); +/// ``` +/// +/// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut +/// [slices]: slice +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub struct SplitLeftInclusiveMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusiveMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl fmt::Debug for SplitLeftInclusiveMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitLeftInclusiveMut") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, T, P> Iterator for SplitLeftInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + + // The first index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the right. + let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] }; + remainder.iter().position(|x| (*pred)(x)).map(|x| x + 1) + }; + let idx = idx_opt.unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = tail; + Some(head) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice. + // If it matches every element, we yield `len()` one-element slices, + // or a single empty slice. + (1, Some(cmp::max(1, self.v.len()))) + } + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = if self.v.is_empty() { + None + } else { + // work around borrowsck limitations + let pred = &mut self.pred; + + self.v.iter().rposition(|x| (*pred)(x)) + }; + let idx = idx_opt.unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(tail) + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl FusedIterator for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} + /// An iterator over subslices separated by elements that match a predicate /// function, starting from the end of the slice. /// diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 77fd1ec2b8ea2..bbf539d95fcd3 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -65,6 +65,9 @@ pub use iter::{GroupBy, GroupByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub use iter::{SplitLeftInclusive, SplitLeftInclusiveMut}; + #[stable(feature = "rust1", since = "1.0.0")] pub use raw::{from_raw_parts, from_raw_parts_mut}; @@ -1969,6 +1972,71 @@ impl [T] { SplitInclusiveMut::new(self, pred) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the start of the next + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_left_inclusive)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the initiator of a new slice. + /// That slice will be the last item returned by the iterator. + /// + /// ``` + /// #![feature(split_left_inclusive)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_left_inclusive", issue = "none")] + #[inline] + pub fn split_left_inclusive(&self, pred: F) -> SplitLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitLeftInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the next + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_left_inclusive)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_left_inclusive_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_left_inclusive", issue = "none")] + #[inline] + pub fn split_left_inclusive_mut(&mut self, pred: F) -> SplitLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitLeftInclusiveMut::new(self, pred) + } + /// Returns an iterator over subslices separated by elements that match /// `pred`, starting at the end of the slice and working backwards. /// The matched element is not contained in the subslices. From 13242ef11764f79937f600e5307e1333c689213b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 5 Dec 2021 11:39:58 -0500 Subject: [PATCH 02/10] Return empty slice on empty slice input (match #89716) --- library/alloc/tests/slice.rs | 8 ++++---- library/core/src/slice/iter.rs | 6 ++++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 2f35568f24e8d..ed7165ea6c569 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -943,7 +943,7 @@ fn test_splitator_left_inclusive() { assert_eq!(xs.split_left_inclusive(|_| true).collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_left_inclusive(|x| *x == 5).collect::>(), splits); } @@ -963,7 +963,7 @@ fn test_splitator_left_inclusive_reverse() { assert_eq!(xs.split_left_inclusive(|_| true).rev().collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_left_inclusive(|x| *x == 5).rev().collect::>(), splits); } @@ -983,7 +983,7 @@ fn test_splitator_left_inclusive_mut() { assert_eq!(xs.split_left_inclusive_mut(|_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).collect::>(), splits); } @@ -1003,7 +1003,7 @@ fn test_splitator_left_inclusive_reverse_mut() { assert_eq!(xs.split_left_inclusive_mut(|_| true).rev().collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); } diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 7f480905b0d7b..8806cef5de6c9 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -670,7 +670,8 @@ where impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusive<'a, T, P> { #[inline] pub(super) fn new(slice: &'a [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } + let finished = slice.is_empty(); + Self { v: slice, pred, finished } } } @@ -1048,7 +1049,8 @@ where impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusiveMut<'a, T, P> { #[inline] pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } + let finished = slice.is_empty(); + Self { v: slice, pred, finished } } } From f171e92e8124329dbf5710ea44817339dbff11c3 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 5 Dec 2021 11:40:53 -0500 Subject: [PATCH 03/10] Implement `split_left_inclusive` for string slices --- library/alloc/tests/str.rs | 57 ++++++++++++ library/core/src/str/iter.rs | 176 +++++++++++++++++++++++++++++++---- library/core/src/str/mod.rs | 51 +++++++++- 3 files changed, 262 insertions(+), 22 deletions(-) diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index 7379569dd68fe..28ff9aac722d2 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -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"; diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 24083ee6af44f..6335b48aab114 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -563,7 +563,7 @@ pub(super) struct SplitInternal<'a, P: Pattern<'a>> { pub(super) start: usize, pub(super) end: usize, pub(super) matcher: P::Searcher, - pub(super) allow_trailing_empty: bool, + pub(super) allow_bookending_empty: bool, pub(super) finished: bool, } @@ -576,7 +576,7 @@ where .field("start", &self.start) .field("end", &self.end) .field("matcher", &self.matcher) - .field("allow_trailing_empty", &self.allow_trailing_empty) + .field("allow_bookending_empty", &self.allow_bookending_empty) .field("finished", &self.finished) .finish() } @@ -585,7 +585,7 @@ where impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { #[inline] fn get_end(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { + if !self.finished && (self.allow_bookending_empty || self.end - self.start > 0) { self.finished = true; // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. unsafe { @@ -635,6 +635,38 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { } } + #[inline] + fn next_left_inclusive(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + if !self.allow_bookending_empty { + self.allow_bookending_empty = true; + match self.next_left_inclusive() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.start is either the start of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((b, _)) => unsafe { + let elt = haystack.get_unchecked(self.start..b); + self.start = b; + Some(elt) + }, + None => self.get_end(), + } + } + #[inline] fn next_back(&mut self) -> Option<&'a str> where @@ -644,8 +676,8 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { return None; } - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; + if !self.allow_bookending_empty { + self.allow_bookending_empty = true; match self.next_back() { Some(elt) if !elt.is_empty() => return Some(elt), _ => { @@ -681,8 +713,8 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { return None; } - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; + if !self.allow_bookending_empty { + self.allow_bookending_empty = true; match self.next_back_inclusive() { Some(elt) if !elt.is_empty() => return Some(elt), _ => { @@ -715,6 +747,40 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { } } + #[inline] + fn next_back_left_inclusive(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((b, _)) => unsafe { + let elt = haystack.get_unchecked(b..self.end); + self.end = b; + if self.start == b { + self.finished = true; + } + Some(elt) + }, + // SAFETY: self.start is either the start of the original string, + // or start of a substring that represents the part of the string that hasn't + // iterated yet. Either way, it is guaranteed to lie on unicode boundary. + // self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + None => unsafe { + self.finished = true; + Some(haystack.get_unchecked(self.start..self.end)) + }, + } + } + #[inline] fn as_str(&self) -> &'a str { // `Self::get_end` doesn't change `self.start` @@ -1190,18 +1256,6 @@ pub struct SplitAsciiWhitespace<'a> { Map, BytesIsNotEmpty>, UnsafeBytesToStr>, } -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_inclusive`]: str::split_inclusive -#[stable(feature = "split_inclusive", since = "1.51.0")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); - #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; @@ -1319,6 +1373,18 @@ impl<'a> SplitAsciiWhitespace<'a> { } } +/// An iterator over the substrings of a string, +/// terminated by a substring matching to a predicate function +/// Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_inclusive`]: str::split_inclusive +#[stable(feature = "split_inclusive", since = "1.51.0")] +pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); + #[stable(feature = "split_inclusive", since = "1.51.0")] impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { type Item = &'a str; @@ -1378,6 +1444,78 @@ impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { } } +/// An iterator over the substrings of a string, +/// terminated by a substring matching to a predicate function +/// Unlike `Split`, it contains the matched part as an initiator +/// of the subslice. +/// +/// This struct is created by the [`split_left_inclusive`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_left_inclusive`]: str::split_left_inclusive +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub struct SplitLeftInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, P: Pattern<'a>> Iterator for SplitLeftInclusive<'a, P> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next_left_inclusive() + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitLeftInclusive<'a, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitLeftInclusive").field("0", &self.0).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitLeftInclusive<'a, P> { + fn clone(&self) -> Self { + SplitLeftInclusive(self.0.clone()) + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator + for SplitLeftInclusive<'a, P> +{ + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back_left_inclusive() + } +} + +#[unstable(feature = "split_left_inclusive", issue = "none")] +impl<'a, P: Pattern<'a>> FusedIterator for SplitLeftInclusive<'a, P> {} + +impl<'a, P: Pattern<'a>> SplitLeftInclusive<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_left_inclusive)] + /// let mut split = "Mary had a little lamb".split_left_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), " had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c4f2e283eb3bc..33b4c0e4d2d72 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -69,6 +69,9 @@ pub use iter::SplitAsciiWhitespace; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::SplitInclusive; +#[unstable(feature = "split_left_inclusive", issue = "none")] +pub use iter::SplitLeftInclusive; + #[unstable(feature = "str_internals", issue = "none")] pub use validations::{next_code_point, utf8_char_width}; @@ -1327,7 +1330,7 @@ impl str { start: 0, end: self.len(), matcher: pat.into_searcher(self), - allow_trailing_empty: true, + allow_bookending_empty: true, finished: false, }) } @@ -1367,11 +1370,53 @@ impl str { start: 0, end: self.len(), matcher: pat.into_searcher(self), - allow_trailing_empty: false, + allow_bookending_empty: false, finished: false, }) } + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern. Differs from the iterator produced by + /// `split` in that `split_left_inclusive` leaves the matched part as the + /// initiator of the substring. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Examples + /// + /// ``` + /// #![feature(split_left_inclusive)] + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .split_left_inclusive('\n').collect(); + /// assert_eq!(v, ["Mary had a little lamb", "\nlittle lamb", "\nlittle lamb."]); + /// ``` + /// + /// If the last element of the string is matched, + /// that element will be considered the initiator of a new substring. + /// That substring will be the last item returned by the iterator. + /// + /// ``` + /// #![feature(split_left_inclusive)] + /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .split_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\nMary had a little lamb", "\nlittle lamb", "\nlittle lamb.", "\n"]); + /// ``` + #[unstable(feature = "split_left_inclusive", issue = "none")] + #[inline] + pub fn split_left_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitLeftInclusive<'a, P> { + SplitLeftInclusive(SplitInternal { + start: 0, + end: self.len(), + matcher: pat.into_searcher(self), + allow_bookending_empty: false, + finished: self.is_empty(), + }) + } + /// An iterator over substrings of the given string slice, separated by /// characters matched by a pattern and yielded in reverse order. /// @@ -1469,7 +1514,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { allow_trailing_empty: false, ..self.split(pat).0 }) + SplitTerminator(SplitInternal { allow_bookending_empty: false, ..self.split(pat).0 }) } /// An iterator over substrings of `self`, separated by characters From 8d1308cd3297155926c281cf50fb1707c3f870c6 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 5 Dec 2021 16:53:50 -0500 Subject: [PATCH 04/10] Implement reversed variants of all `split_inclusive` slice methods --- library/alloc/src/lib.rs | 2 +- library/alloc/src/slice.rs | 9 +- library/alloc/tests/lib.rs | 2 +- library/alloc/tests/slice.rs | 160 ++++++ library/core/src/slice/iter.rs | 794 ++++++++++++++------------ library/core/src/slice/iter/macros.rs | 156 ++++- library/core/src/slice/mod.rs | 370 +++++++++++- library/core/src/str/iter.rs | 14 +- library/core/src/str/mod.rs | 8 +- 9 files changed, 1129 insertions(+), 386 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 3b770f5cf382b..60a55640667ca 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -133,7 +133,7 @@ #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(slice_range)] -#![feature(split_left_inclusive)] +#![feature(split_inclusive_variants)] #![feature(str_internals)] #![feature(strict_provenance)] #![feature(trusted_len)] diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 64d92f7cbb77f..75138a7a16fa0 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -132,12 +132,17 @@ 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")] pub use core::slice::{SplitInclusive, SplitInclusiveMut}; -#[unstable(feature = "split_left_inclusive", issue = "none")] -pub use core::slice::{SplitLeftInclusive, SplitLeftInclusiveMut}; //////////////////////////////////////////////////////////////////////////////// // Basic slice extension methods diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 084aadc55170f..53a39cc0a8986 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -42,7 +42,7 @@ #![feature(bench_black_box)] #![feature(strict_provenance)] #![feature(once_cell)] -#![feature(split_left_inclusive)] +#![feature(split_inclusive_variants)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index ed7165ea6c569..68af35c576bd5 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1007,6 +1007,166 @@ fn test_splitator_left_inclusive_reverse_mut() { assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[2, 3, 4, 5], &[1]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1], &[2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[&[]]; + assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_left_inclusive(|_| true).collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive(|_| true).rev().collect::>(), splits); + + let xs: &[i32] = &[]; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive(|x| *x == 5).rev().collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[1, 2, 3, 4]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).collect::>(), splits); + let splits: &[&[_]] = &[&[5], &[4], &[3], &[2], &[1]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).collect::>(), 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::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 1).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1, 2, 3, 4, 5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|x| *x == 10).rev().collect::>(), splits); + let splits: &[&[_]] = &[&[1], &[2], &[3], &[4], &[5]]; + assert_eq!(xs.rsplit_left_inclusive_mut(|_| true).rev().collect::>(), splits); + + let xs: &mut [i32] = &mut []; + let splits: &[&[i32]] = &[]; + assert_eq!(xs.split_left_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); +} + #[test] fn test_splitnator() { let xs = &[1, 2, 3, 4, 5]; diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 8806cef5de6c9..5b2f32bc56ca4 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -640,6 +640,21 @@ where #[stable(feature = "split_inclusive", since = "1.51.0")] impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} +impl<'a, T, P> SplitIter for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(self.v) + } + } +} + /// An iterator over subslices separated by elements that match a predicate /// function. Unlike `Split`, it contains the matched part as an initiator /// of the subslice. @@ -649,7 +664,7 @@ impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool /// # Example /// /// ``` -/// #![feature(split_left_inclusive)] +/// #![feature(split_inclusive_variants)] /// /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); @@ -657,7 +672,7 @@ impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool /// /// [`split_left_inclusive`]: slice::split_left_inclusive /// [slices]: slice -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] pub struct SplitLeftInclusive<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -675,7 +690,7 @@ impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusive<'a, T, P> { } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl fmt::Debug for SplitLeftInclusive<'_, T, P> where P: FnMut(&T) -> bool, @@ -689,7 +704,7 @@ where } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl Clone for SplitLeftInclusive<'_, T, P> where P: Clone + FnMut(&T) -> bool, @@ -699,7 +714,7 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, T, P> Iterator for SplitLeftInclusive<'a, T, P> where P: FnMut(&T) -> bool, @@ -740,7 +755,7 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusive<'a, T, P> where P: FnMut(&T) -> bool, @@ -761,9 +776,24 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl FusedIterator for SplitLeftInclusive<'_, T, P> where P: FnMut(&T) -> bool {} +impl<'a, T, P> SplitIter for SplitLeftInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(self.v) + } + } +} + /// An iterator over the mutable subslices of the vector which are separated /// by elements that match `pred`. /// @@ -1018,6 +1048,21 @@ where #[stable(feature = "split_inclusive", since = "1.51.0")] impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} +impl<'a, T, P> SplitIter for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(mem::replace(&mut self.v, &mut [])) + } + } +} + /// An iterator over the mutable subslices of the vector which are separated /// by elements that match `pred`. Unlike `SplitMut`, it contains the matched /// parts in the beginnings of the subslices. @@ -1028,7 +1073,7 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// # Example /// /// ``` -/// #![feature(split_left_inclusive)] +/// #![feature(split_inclusive_variants)] /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0); @@ -1036,7 +1081,7 @@ impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> b /// /// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut /// [slices]: slice -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] pub struct SplitLeftInclusiveMut<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -1054,7 +1099,7 @@ impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusiveMut<'a, T, P> { } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl fmt::Debug for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool, @@ -1067,7 +1112,7 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, T, P> Iterator for SplitLeftInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool, @@ -1113,7 +1158,7 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool, @@ -1143,196 +1188,150 @@ where } } -#[unstable(feature = "split_left_inclusive", issue = "none")] -impl FusedIterator for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit(|num| *num == 0); -/// ``` -/// -/// [`rsplit`]: slice::rsplit -/// [slices]: slice -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplit<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: Split<'a, T, P>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - Self { inner: Split::new(slice, pred) } - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplit<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplit") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl Clone for RSplit<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - RSplit { inner: self.inner.clone() } - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the subslices of the vector which are separated -/// by elements that match `pred`, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [11, 22, 33, 0, 44, 55]; -/// let iter = slice.rsplit_mut(|num| *num == 0); -/// ``` -/// -/// [`rsplit_mut`]: slice::rsplit_mut -/// [slices]: slice -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: SplitMut<'a, T, P>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - Self { inner: SplitMut::new(slice, pred) } - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitMut") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> +impl<'a, T, P> SplitIter for SplitLeftInclusiveMut<'a, T, P> where P: FnMut(&T) -> bool, { #[inline] fn finish(&mut self) -> Option<&'a mut [T]> { - self.inner.finish() + if self.finished { + None + } else { + self.finished = true; + Some(mem::replace(&mut self.v, &mut [])) + } } } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} +#[unstable(feature = "split_inclusive_variants", issue = "none")] +impl FusedIterator for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - self.inner.next() - } +reverse_iter! { + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, starting from the end of the slice. + /// + /// This struct is created by the [`rsplit`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let iter = slice.rsplit(|num| *num == 0); + /// ``` + /// + /// [`rsplit`]: slice::rsplit + /// [slices]: slice + pub struct RSplit { "RSplit"; Split }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order. Unlike `Split`, it contains the matched part as + /// an initiator of the subslice. + /// + /// This struct is created by the [`rsplit_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive`]: slice::rsplit_inclusive + /// [slices]: slice + pub struct RSplitInclusive { "RSplitInclusive"; SplitInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order. Unlike `Split`, it contains the matched part as + /// an initiator of the subslice. + /// + /// This struct is created by the [`rsplit_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive`]: slice::rsplit_left_inclusive + /// [slices]: slice + pub struct RSplitLeftInclusive { "RSplitLeftInclusive"; SplitLeftInclusive }: Clone + + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the subslices of the vector which are separated + /// by elements that match `pred`, starting from the end of the slice. + /// + /// This struct is created by the [`rsplit_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [11, 22, 33, 0, 44, 55]; + /// let iter = slice.rsplit_mut(|num| *num == 0); + /// ``` + /// + /// [`rsplit_mut`]: slice::rsplit_mut + /// [slices]: slice + pub struct RSplitMut { "RSplitMut"; SplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`, in reverse order. Unlike `SplitMut`, it + /// contains the matched parts in the ends of the subslices. + /// + /// This struct is created by the [`rsplit_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.rsplit_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`rsplit_inclusive_mut`]: slice::rsplit_inclusive_mut + /// [slices]: slice + pub struct RSplitInclusiveMut { "RSplitInclusiveMut" ; SplitInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`, in reverse order. Unlike `SplitMut`, it + /// contains the matched parts in the beginnings of the subslices. + /// + /// This struct is created by the [`rsplit_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.rsplit_left_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`rsplit_left_inclusive_mut`]: slice::rsplit_left_inclusive_mut + /// [slices]: slice + pub struct RSplitLeftInclusiveMut { "RSplitLeftInclusiveMut" ; SplitLeftInclusiveMut } } -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - /// An private iterator over subslices separated by elements that /// match a predicate function, splitting at most a fixed number of /// times. -#[derive(Debug)] +#[derive(Clone, Debug)] struct GenericSplitN { iter: I, count: usize, @@ -1366,173 +1365,262 @@ impl> Iterator for GenericSplitN { } } -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`splitn`]: slice::splitn -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { - #[inline] - pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`rsplitn`]: slice::rsplitn -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { - #[inline] - pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`splitn_mut`]: slice::splitn_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { - #[inline] - pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNMut").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut slice = [10, 40, 30, 20, 60, 50]; -/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); -/// ``` -/// -/// [`rsplitn_mut`]: slice::rsplitn_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct RSplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { - #[inline] - pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { - Self { inner: GenericSplitN { iter: s, count: n } } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() - } +iter_n! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a given number of splits. + /// + /// This struct is created by the [`splitn`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.splitn(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`splitn`]: slice::splitn + /// [slices]: slice + pub struct SplitN {"SplitN"; Split }: Clone + + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a + /// predicate function, limited to a given number of splits, starting + /// from the end of the slice. + /// + /// This struct is created by the [`rsplitn`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.rsplitn(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`rsplitn`]: slice::rsplitn + /// [slices]: slice + pub struct RSplitN {"RSplitN"; RSplit }: Clone + + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a given number of splits. + /// + /// This struct is created by the [`splitn_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`splitn_mut`]: slice::splitn_mut + /// [slices]: slice + pub struct SplitNMut {"SplitNMut"; SplitMut } + + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a + /// predicate function, limited to a given number of splits, starting + /// from the end of the slice. + /// + /// This struct is created by the [`rsplitn_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut slice = [10, 40, 30, 20, 60, 50]; + /// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); + /// ``` + /// + /// [`rsplitn_mut`]: slice::rsplitn_mut + /// [slices]: slice + pub struct RSplitNMut {"RSplitNMut"; RSplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitN`, it + /// contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`splitn_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_inclusive`]: slice::splitn_inclusive + /// [slices]: slice + pub struct SplitNInclusive {"SplitNInclusive"; SplitInclusive}: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitN`, it + /// contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`splitn_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_left_inclusive`]: slice::splitn_left_inclusive + /// [slices]: slice + pub struct SplitNLeftInclusive {"SplitNLeftInclusive"; SplitLeftInclusive}: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`rsplitn_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_inclusive`]: slice::rsplitn_inclusive + /// [slices]: slice + pub struct RSplitNInclusive {"RSplitNInclusive"; RSplitInclusive}: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`rsplitn_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_left_inclusive`]: slice::rsplitn_left_inclusive + /// [slices]: slice + pub struct RSplitNLeftInclusive {"RSplitNLeftInclusive"; RSplitLeftInclusive}: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitNMut`, it + /// contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`splitn_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_inclusive_mut`]: slice::splitn_inclusive_mut + /// [slices]: slice + pub struct SplitNInclusiveMut {"SplitNInclusiveMut"; SplitInclusiveMut} + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, limited to a certain number of elements. Unlike `SplitNMut`, it + /// contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`splitn_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.splitn_left_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`splitn_left_inclusive_mut`]: slice::splitn_left_inclusive_mut + /// [slices]: slice + pub struct SplitNLeftInclusiveMut {"SplitNLeftInclusiveMut"; SplitLeftInclusiveMut} + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as a terminator of the subslice. + /// + /// This struct is created by the [`rsplitn_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_inclusive_mut`]: slice::rsplitn_inclusive_mut + /// [slices]: slice + pub struct RSplitNInclusiveMut {"RSplitNInclusiveMut"; RSplitInclusiveMut} + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function, in reverse order, limited to a certain number of elements. Unlike + /// `RSplitN`, it contains the matched part as an initiator of the subslice. + /// + /// This struct is created by the [`rsplitn_left_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive_mut(2, |num| num % 3 == 0); + /// ``` + /// + /// [`rsplitn_left_inclusive_mut`]: slice::rsplitn_left_inclusive_mut + /// [slices]: slice + pub struct RSplitNLeftInclusiveMut {"RSplitNLeftInclusiveMut"; RSplitLeftInclusiveMut} } -forward_iterator! { SplitN: T, &'a [T] } -forward_iterator! { RSplitN: T, &'a [T] } -forward_iterator! { SplitNMut: T, &'a mut [T] } -forward_iterator! { RSplitNMut: T, &'a mut [T] } - /// An iterator over overlapping subslices of length `size`. /// /// This struct is created by the [`windows`] method on [slices]. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index c05242222dde7..e022badf68cbb 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -397,17 +397,155 @@ macro_rules! iterator { } } -macro_rules! forward_iterator { - ($name:ident: $elem:ident, $iter_of:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, $elem, P> Iterator for $name<'a, $elem, P> +macro_rules! reverse_iter { + ($( + #[$stablility:meta] + $(#[$outer:meta])* + $vis:vis struct $rev:ident { $str:literal ; $inner:ident } $(: $clone:ident)? + )*) => {$( + $(#[$outer])* + #[$stablility] + $vis struct $rev<'a, T: 'a, P> where P: FnMut(&T) -> bool, { - type Item = $iter_of; + inner: $inner<'a, T, P>, + } + impl<'a, T: 'a, P: FnMut(&T) -> bool> $rev<'a, T, P> { #[inline] - fn next(&mut self) -> Option<$iter_of> { + pub(super) fn new(slice: <$inner<'a, T, P> as Iterator>::Item, pred: P) -> Self { + Self { inner: $inner::new(slice, pred) } + } + } + + #[$stablility] + impl fmt::Debug for $rev<'_, T, P> + where + P: FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct($str) + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } + } + + $( + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` + #[$stablility] + impl<'a, T, P> $clone for $rev<'a, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } + } + )? + + #[$stablility] + impl<'a, T, P> Iterator for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = <$inner<'a, T, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + #[$stablility] + impl<'a, T, P> DoubleEndedIterator for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn next_back(&mut self) -> Option { + self.inner.next() + } + } + + #[$stablility] + impl FusedIterator for $rev<'_, T, P> where P: FnMut(&T) -> bool {} + + #[$stablility] + impl<'a, T, P> SplitIter for $rev<'a, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn finish(&mut self) -> Option { + self.inner.finish() + } + } + )*}; +} + +#[allow(unused)] +macro_rules! iter_n { + ($( + #[$stablility:meta] + #[fused($fused_stablility:meta)] + $(#[$outer:meta])* + $vis:vis struct $iter_n:ident { $str:literal ; $inner:ident } $(: $clone:ident)? + )*) => {$( + $(#[$outer])* + #[$stablility] + pub struct $iter_n<'a, T: 'a, P> + where + P: FnMut(&T) -> bool, + { + inner: GenericSplitN<$inner<'a, T, P>>, + } + + impl<'a, T: 'a, P: FnMut(&T) -> bool> $iter_n<'a, T, P> { + #[inline] + pub(super) fn new(s: $inner<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } + } + + $( + #[$stablility] + impl<'a, T: 'a, P> $clone for $iter_n<'a, T, P> + where + P: FnMut(&T) -> bool, + $inner<'a, T, P>: Clone, + { + fn clone(&self) -> Self { + Self { inner: self.inner.clone() } + } + } + )? + + #[$stablility] + impl fmt::Debug for $iter_n<'_, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct($str).field("inner", &self.inner).finish() + } + } + + #[$stablility] + impl<'a, T, P> Iterator for $iter_n<'a, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = <$inner<'a, T, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } @@ -417,7 +555,7 @@ macro_rules! forward_iterator { } } - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} - }; + #[$fused_stablility] + impl<'a, T, P> FusedIterator for $iter_n<'a, T, P> where P: FnMut(&T) -> bool {} + )*}; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index bbf539d95fcd3..b789e05bd5690 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -65,8 +65,13 @@ pub use iter::{GroupBy, GroupByMut}; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::{SplitInclusive, SplitInclusiveMut}; -#[unstable(feature = "split_left_inclusive", issue = "none")] -pub use iter::{SplitLeftInclusive, SplitLeftInclusiveMut}; +#[unstable(feature = "split_inclusive_variants", issue = "none")] +pub use iter::{ + RSplitInclusive, RSplitInclusiveMut, RSplitLeftInclusive, RSplitLeftInclusiveMut, + RSplitNInclusive, RSplitNInclusiveMut, RSplitNLeftInclusive, RSplitNLeftInclusiveMut, + SplitLeftInclusive, SplitLeftInclusiveMut, SplitNInclusive, SplitNInclusiveMut, + SplitNLeftInclusive, SplitNLeftInclusiveMut, +}; #[stable(feature = "rust1", since = "1.0.0")] pub use raw::{from_raw_parts, from_raw_parts_mut}; @@ -1955,6 +1960,8 @@ impl [T] { /// # Examples /// /// ``` + /// #![feature(split_inclusive_variants)] + /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { @@ -1973,13 +1980,13 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`. The matched element is contained in the start of the next + /// `pred`. The matched element is contained in the start of the following /// subslice as an initiator. /// /// # Examples /// /// ``` - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// /// let slice = [10, 40, 33, 20]; /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); @@ -1994,7 +2001,7 @@ impl [T] { /// That slice will be the last item returned by the iterator. /// /// ``` - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// /// let slice = [3, 10, 40, 33]; /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); @@ -2003,7 +2010,7 @@ impl [T] { /// assert_eq!(iter.next().unwrap(), &[33]); /// assert!(iter.next().is_none()); /// ``` - #[unstable(feature = "split_left_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] pub fn split_left_inclusive(&self, pred: F) -> SplitLeftInclusive<'_, T, F> where @@ -2013,13 +2020,13 @@ impl [T] { } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`. The matched element is contained in the next + /// match `pred`. The matched element is contained in the following /// subslice as an initiator. /// /// # Examples /// /// ``` - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// @@ -2028,7 +2035,7 @@ impl [T] { /// } /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); /// ``` - #[unstable(feature = "split_left_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] pub fn split_left_inclusive_mut(&mut self, pred: F) -> SplitLeftInclusiveMut<'_, T, F> where @@ -2099,6 +2106,137 @@ impl [T] { RSplitMut::new(self, pred) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order. The matched element is contained in the end + /// of the previous subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_inclusive(&self, pred: F) -> RSplitInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_inclusive_mut(&mut self, pred: F) -> RSplitInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitInclusiveMut::new(self, pred) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order. The matched element is contained in the start + /// of the following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// If the last element of the slice is matched, + /// that element will be considered the initiator of a new slice. + /// That slice will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 10, 40, 33]; + /// let mut iter = slice.rsplit_left_inclusive(|num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33]); + /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_left_inclusive(&self, pred: F) -> RSplitLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitLeftInclusive::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplit_left_inclusive_mut(|num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_left_inclusive_mut(&mut self, pred: F) -> RSplitLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitLeftInclusiveMut::new(self, pred) + } + /// Returns an iterator over subslices separated by elements that match /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. @@ -2209,6 +2347,220 @@ impl [T] { RSplitNMut::new(self.rsplit_mut(pred), n) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the end of the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20, 30]; + /// let mut iter = slice.splitn_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[20, 30]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive(&self, n: usize, pred: F) -> SplitNInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNInclusive::new(self.split_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the previous + /// subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.splitn_inclusive_mut(2, |num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 1, 20, 60, 1]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive_mut(&mut self, n: usize, pred: F) -> SplitNInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNInclusiveMut::new(self.split_inclusive_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`. The matched element is contained in the start of the following + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20, 9]; + /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20, 9]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive(&self, n: usize, pred: F) -> SplitNLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNLeftInclusive::new(self.split_left_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`. The matched element is contained in the following + /// subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50, 90]; + /// + /// for group in v.splitn_left_inclusive_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 1, 20, 60, 50, 90]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive_mut( + &mut self, + n: usize, + pred: F, + ) -> SplitNLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + SplitNLeftInclusiveMut::new(self.split_left_inclusive_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order, limited to returning at most `n` items. The + /// matched element is contained in the end of the previous subslice as a + /// terminator. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [20, 60, 10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[20, 60, 10, 40, 33]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive(&self, n: usize, pred: F) -> RSplitNInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNInclusive::new(self.rsplit_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn_inclusive_mut(2, |num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; + /// } + /// assert_eq!(v, [10, 40, 30, 20, 1, 1]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive_mut(&mut self, n: usize, pred: F) -> RSplitNInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNInclusiveMut::new(self.rsplit_inclusive_mut(pred), n) + } + + /// Returns an iterator over subslices separated by elements that match + /// `pred`, in reverse order. The matched element is contained in the start + /// of the following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [3, 9, 10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_left_inclusive(2, |num| num % 3 == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert_eq!(iter.next().unwrap(), &[3, 9, 10, 40]); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive(&self, n: usize, pred: F) -> RSplitNLeftInclusive<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNLeftInclusive::new(self.rsplit_left_inclusive(pred), n) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, in reverse order. The matched element is contained in the + /// following subslice as an initiator. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// + /// for group in v.rsplitn_left_inclusive_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; + /// } + /// assert_eq!(v, [1, 40, 30, 20, 1, 50]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive_mut( + &mut self, + n: usize, + pred: F, + ) -> RSplitNLeftInclusiveMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitNLeftInclusiveMut::new(self.rsplit_left_inclusive_mut(pred), n) + } + /// Returns `true` if the slice contains an element with the given value. /// /// This operation is *O*(*n*). diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 6335b48aab114..2a048b5044e6e 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1453,10 +1453,10 @@ impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { /// See its documentation for more. /// /// [`split_left_inclusive`]: str::split_left_inclusive -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] pub struct SplitLeftInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, P: Pattern<'a>> Iterator for SplitLeftInclusive<'a, P> { type Item = &'a str; @@ -1466,7 +1466,7 @@ impl<'a, P: Pattern<'a>> Iterator for SplitLeftInclusive<'a, P> { } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitLeftInclusive<'a, P> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SplitLeftInclusive").field("0", &self.0).finish() @@ -1474,14 +1474,14 @@ impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitLeftInclusive } // FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitLeftInclusive<'a, P> { fn clone(&self) -> Self { SplitLeftInclusive(self.0.clone()) } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator for SplitLeftInclusive<'a, P> { @@ -1491,7 +1491,7 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator } } -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] impl<'a, P: Pattern<'a>> FusedIterator for SplitLeftInclusive<'a, P> {} impl<'a, P: Pattern<'a>> SplitLeftInclusive<'a, P> { @@ -1501,7 +1501,7 @@ impl<'a, P: Pattern<'a>> SplitLeftInclusive<'a, P> { /// /// ``` /// #![feature(str_split_inclusive_as_str)] - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// let mut split = "Mary had a little lamb".split_left_inclusive(' '); /// assert_eq!(split.as_str(), "Mary had a little lamb"); /// split.next(); diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 33b4c0e4d2d72..441a2733f5d0f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -69,7 +69,7 @@ pub use iter::SplitAsciiWhitespace; #[stable(feature = "split_inclusive", since = "1.51.0")] pub use iter::SplitInclusive; -#[unstable(feature = "split_left_inclusive", issue = "none")] +#[unstable(feature = "split_inclusive_variants", issue = "none")] pub use iter::SplitLeftInclusive; #[unstable(feature = "str_internals", issue = "none")] @@ -1389,7 +1389,7 @@ impl str { /// # Examples /// /// ``` - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." /// .split_left_inclusive('\n').collect(); /// assert_eq!(v, ["Mary had a little lamb", "\nlittle lamb", "\nlittle lamb."]); @@ -1400,12 +1400,12 @@ impl str { /// That substring will be the last item returned by the iterator. /// /// ``` - /// #![feature(split_left_inclusive)] + /// #![feature(split_inclusive_variants)] /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" /// .split_left_inclusive('\n').collect(); /// assert_eq!(v, ["\nMary had a little lamb", "\nlittle lamb", "\nlittle lamb.", "\n"]); /// ``` - #[unstable(feature = "split_left_inclusive", issue = "none")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] pub fn split_left_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitLeftInclusive<'a, P> { SplitLeftInclusive(SplitInternal { From 619283a2d052617ff69234ee5d3bb6d81e8b8c7b Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Sun, 19 Dec 2021 16:34:35 -0500 Subject: [PATCH 05/10] Update tests following #89825 --- library/alloc/tests/slice.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 68af35c576bd5..d55d53be7bc30 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1023,7 +1023,7 @@ fn test_rsplitator_inclusive() { assert_eq!(xs.rsplit_inclusive(|_| true).collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.rsplit_inclusive(|x| *x == 5).collect::>(), splits); } @@ -1043,7 +1043,7 @@ fn test_rsplitator_inclusive_reverse() { assert_eq!(xs.rsplit_inclusive(|_| true).rev().collect::>(), splits); let xs: &[i32] = &[]; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.rsplit_inclusive(|x| *x == 5).rev().collect::>(), splits); } @@ -1063,7 +1063,7 @@ fn test_rsplitator_mut_inclusive() { assert_eq!(xs.rsplit_inclusive_mut(|_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).collect::>(), splits); } @@ -1083,7 +1083,7 @@ fn test_rsplitator_mut_inclusive_reverse() { assert_eq!(xs.rsplit_inclusive_mut(|_| true).rev().collect::>(), splits); let xs: &mut [i32] = &mut []; - let splits: &[&[i32]] = &[&[]]; + let splits: &[&[i32]] = &[]; assert_eq!(xs.rsplit_inclusive_mut(|x| *x == 5).rev().collect::>(), splits); } From 0bcf4e4699e9e29f15821aa560813389f237ada0 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 22 Dec 2021 01:56:18 -0500 Subject: [PATCH 06/10] Implement all iterator variants for string slices --- library/alloc/src/str.rs | 5 + library/core/src/str/iter.rs | 787 +++++++++++++++++------------------ library/core/src/str/mod.rs | 35 +- 3 files changed, 402 insertions(+), 425 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index d5ed2c4adf4f1..84fe88a0ce755 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -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, + SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, +}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 2a048b5044e6e..a105b954f82c8 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -413,18 +413,18 @@ macro_rules! generate_pattern_iterators { { // Forward iterator forward: + #[$forward_stability_attribute:meta] + #[fused($fused_forward_stability_attribute:meta)] $(#[$forward_iterator_attribute:meta])* struct $forward_iterator:ident; // Reverse iterator reverse: + #[$reverse_stability_attribute:meta] + #[fused($fused_reverse_stability_attribute:meta)] $(#[$reverse_iterator_attribute:meta])* struct $reverse_iterator:ident; - // Stability of all generated items - stability: - $(#[$common_stability_attribute:meta])* - // Internal almost-iterator that is being delegated to internal: $internal_iterator:ident yielding ($iterty:ty); @@ -433,10 +433,10 @@ macro_rules! generate_pattern_iterators { delegate $($t:tt)* } => { $(#[$forward_iterator_attribute])* - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] impl<'a, P> fmt::Debug for $forward_iterator<'a, P> where P: Pattern<'a, Searcher: fmt::Debug>, @@ -448,17 +448,18 @@ macro_rules! generate_pattern_iterators { } } - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { type Item = $iterty; #[inline] - fn next(&mut self) -> Option<$iterty> { + fn next(&mut self) -> Option { self.0.next() } } - $(#[$common_stability_attribute])* + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` + #[$forward_stability_attribute] impl<'a, P> Clone for $forward_iterator<'a, P> where P: Pattern<'a, Searcher: Clone>, @@ -469,10 +470,10 @@ macro_rules! generate_pattern_iterators { } $(#[$reverse_iterator_attribute])* - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: fmt::Debug>, @@ -484,7 +485,7 @@ macro_rules! generate_pattern_iterators { } } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> Iterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, @@ -492,12 +493,12 @@ macro_rules! generate_pattern_iterators { type Item = $iterty; #[inline] - fn next(&mut self) -> Option<$iterty> { + fn next(&mut self) -> Option { self.0.next_back() } } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> Clone for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: Clone>, @@ -507,305 +508,247 @@ macro_rules! generate_pattern_iterators { } } - #[stable(feature = "fused", since = "1.26.0")] + #[$fused_forward_stability_attribute] impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - #[stable(feature = "fused", since = "1.26.0")] + #[$fused_reverse_stability_attribute] impl<'a, P> FusedIterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, {} - generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, - $forward_iterator, - $reverse_iterator, $iterty); + generate_pattern_iterators!($($t)* with + #[$forward_stability_attribute] + $forward_iterator, + #[$reverse_stability_attribute] + $reverse_iterator, + yielding $iterty + ); }; { - double ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty + double ended; with + #[$forward_stability_attribute:meta] + $forward_iterator:ident, + #[$reverse_stability_attribute:meta] + $reverse_iterator:ident, + yielding $iterty:ty } => { - $(#[$common_stability_attribute])* + #[$forward_stability_attribute] impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> where P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] - fn next_back(&mut self) -> Option<$iterty> { + fn next_back(&mut self) -> Option<::Item> { self.0.next_back() } } - $(#[$common_stability_attribute])* + #[$reverse_stability_attribute] impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, { #[inline] - fn next_back(&mut self) -> Option<$iterty> { + fn next_back(&mut self) -> Option<::Item> { self.0.next() } } }; { - single ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty + single ended; with + #[$forward_stability_attribute:meta] + $forward_iterator:ident, + #[$reverse_stability_attribute:meta] + $reverse_iterator:ident, + yielding $iterty:ty } => {} } -derive_pattern_clone! { - clone SplitInternal - with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } -} - -pub(super) struct SplitInternal<'a, P: Pattern<'a>> { - pub(super) start: usize, - pub(super) end: usize, - pub(super) matcher: P::Searcher, - pub(super) allow_bookending_empty: bool, - pub(super) finished: bool, -} - -impl<'a, P> fmt::Debug for SplitInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInternal") - .field("start", &self.start) - .field("end", &self.end) - .field("matcher", &self.matcher) - .field("allow_bookending_empty", &self.allow_bookending_empty) - .field("finished", &self.finished) - .finish() - } -} - -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { - #[inline] - fn get_end(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_bookending_empty || self.end - self.start > 0) { - self.finished = true; - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { - let string = self.matcher.haystack().get_unchecked(self.start..self.end); - Some(string) - } - } else { - None +macro_rules! split_internal { + ( + $split_struct:ident { + debug: $name_str:literal, + $(skip_leading_empty: $skip_leading_empty:ident,)? + $(skip_trailing_empty: $skip_trailing_empty:ident,)? + include_leading: $include_leading:literal, + include_trailing: $include_trailing:literal, + $(get_end: $get_end:ident,)? } - } - - #[inline] - fn next(&mut self) -> Option<&'a str> { - if self.finished { - return None; + ) => { + pub(super) struct $split_struct<'a, P: Pattern<'a>> { + pub(super) start: usize, + pub(super) end: usize, + pub(super) matcher: P::Searcher, + pub(super) finished: bool, + $(pub(super) $skip_leading_empty: bool,)? + $(pub(super) $skip_trailing_empty: bool,)? } - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..a); - self.start = b; - Some(elt) - }, - None => self.get_end(), + derive_pattern_clone! { + clone $split_struct + with |s| $split_struct { matcher: s.matcher.clone(), ..*s } } - } - #[inline] - fn next_inclusive(&mut self) -> Option<&'a str> { - if self.finished { - return None; + impl<'a, P> fmt::Debug for $split_struct<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct($name_str) + .field("start", &self.start) + .field("end", &self.end) + .field("matcher", &self.matcher) + .field("finished", &self.finished) + $(.field("skip_leading_empty", &self.$skip_leading_empty))? + $(.field("skip_trailing_empty", &self.$skip_trailing_empty))? + .finish() + } } - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.start is either the start of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..b); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } + impl<'a, P: Pattern<'a>> $split_struct<'a, P> { + #[inline] + pub(super) fn new(s: &'a str, pat: P) -> Self { + $split_struct { + start: 0, + end: s.len(), + matcher: pat.into_searcher(s), + finished: false, + $($skip_leading_empty: true,)? + $($skip_trailing_empty: true,)? + } + } - #[inline] - fn next_left_inclusive(&mut self) -> Option<&'a str> { - if self.finished { - return None; - } + #[inline] + fn next(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } - if !self.allow_bookending_empty { - self.allow_bookending_empty = true; - match self.next_left_inclusive() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; + $(if self.$skip_leading_empty { + self.$skip_leading_empty = false; + match self.next() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } } + })? + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let end_idx = if $include_trailing { b } else { a }; + let elt = haystack.get_unchecked(self.start..end_idx); + self.start = if $include_leading { a } else { b }; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + let end = haystack.get_unchecked(self.start..self.end); + self.finished = true; + $(if self.$skip_trailing_empty && end == "" { return None; })? + Some(end) + }, } } - } - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.start is either the start of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((b, _)) => unsafe { - let elt = haystack.get_unchecked(self.start..b); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } - if !self.allow_bookending_empty { - self.allow_bookending_empty = true; - match self.next_back() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; + $(if self.$skip_trailing_empty { + self.$skip_trailing_empty = false; + match self.next_back() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } } + })? + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let start_idx = if $include_leading { a } else { b }; + let elt = haystack.get_unchecked(start_idx..self.end); + self.end = if $include_trailing { b } else { a }; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + let end = haystack.get_unchecked(self.start..self.end); + self.finished = true; + $(if self.$skip_leading_empty && end == "" { return None; })? + Some(end) + }, } } - } - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = a; - Some(elt) - }, - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } - - #[inline] - fn next_back_inclusive(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - if !self.allow_bookending_empty { - self.allow_bookending_empty = true; - match self.next_back_inclusive() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { + $( + #[inline] + fn $get_end(&mut self) -> Option<&'a str> { if self.finished { - return None; + None + } else { + self.finished = true; + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }) } } - } - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = b; - Some(elt) - }, - // SAFETY: self.start is either the start of the original string, - // or start of a substring that represents the part of the string that hasn't - // iterated yet. Either way, it is guaranteed to lie on unicode boundary. - // self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } + )? - #[inline] - fn next_back_left_inclusive(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((b, _)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = b; - if self.start == b { - self.finished = true; + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + #[allow(unused)] // FIXME complete this feature + fn as_str(&self) -> &'a str { + // `Self::get_end` doesn't change `self.start` + if self.finished { + "" + } else { + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } } - Some(elt) - }, - // SAFETY: self.start is either the start of the original string, - // or start of a substring that represents the part of the string that hasn't - // iterated yet. Either way, it is guaranteed to lie on unicode boundary. - // self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, + } } } +} - #[inline] - fn as_str(&self) -> &'a str { - // `Self::get_end` doesn't change `self.start` - if self.finished { - return ""; - } - - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } +split_internal! { + SplitInternal { + debug: "SplitInternal", + include_leading: false, + include_trailing: false, + get_end: get_end, } } generate_pattern_iterators! { forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`split`]. /// /// [`split`]: str::split struct Split; reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rsplit`]. /// /// [`rsplit`]: str::rsplit struct RSplit; - stability: - #[stable(feature = "rust1", since = "1.0.0")] internal: SplitInternal yielding (&'a str); delegate double ended; @@ -853,21 +796,93 @@ impl<'a, P: Pattern<'a>> RSplit<'a, P> { } } +split_internal! { + SplitInclusiveInternal { + debug: "SplitInclusiveInternal", + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: true, + get_end: get_end, + } +} + +generate_pattern_iterators! { + + forward: + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + /// Created with the method [`split_inclusive`]. + /// + /// [`split_inclusive`]: str::split_inclusive + struct SplitInclusive; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_inclusive`]. + /// + /// [`rsplit_inclusive`]: str::rsplit_inclusive + struct RSplitInclusive; + internal: + SplitInclusiveInternal yielding (&'a str); + delegate double ended; +} + +split_internal! { + SplitLeftInclusiveInternal { + debug: "SplitLeftInclusiveInternal", + skip_leading_empty: skip_leading_empty, + include_leading: true, + include_trailing: false, + get_end: get_end, + } +} + +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_left_inclusive`]. + /// + /// [`split_left_inclusive`]: str::split_left_inclusive + struct SplitLeftInclusive; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_left_inclusive`]. + /// + /// [`rsplit_left_inclusive`]: str::rsplit_left_inclusive + struct RSplitLeftInclusive; + internal: + SplitLeftInclusiveInternal yielding (&'a str); + delegate double ended; +} + +split_internal! { + SplitTerminatorInternal { + debug: "SplitTerminatorInternal", + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: false, + } +} + generate_pattern_iterators! { forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`split_terminator`]. /// /// [`split_terminator`]: str::split_terminator struct SplitTerminator; reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rsplit_terminator`]. /// /// [`rsplit_terminator`]: str::rsplit_terminator struct RSplitTerminator; - stability: - #[stable(feature = "rust1", since = "1.0.0")] internal: - SplitInternal yielding (&'a str); + SplitTerminatorInternal yielding (&'a str); delegate double ended; } @@ -913,87 +928,155 @@ impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { } } -derive_pattern_clone! { - clone SplitNInternal - with |s| SplitNInternal { iter: s.iter.clone(), ..*s } +macro_rules! splitn_next { + ($($fn:ident),*) => {$( + #[inline] + fn $fn(&mut self) -> Option<&'a str> { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.$fn() + } + } + } + )*}; } -pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { - pub(super) iter: SplitInternal<'a, P>, - /// The number of splits remaining - pub(super) count: usize, -} +macro_rules! splitn_internal { + ( + struct $splitn_struct:ident { + debug: $debug_str:literal, + iter: $inner_iter:ident, + } + ) => { + derive_pattern_clone! { + clone $splitn_struct + with |s| $splitn_struct { iter: s.iter.clone(), ..*s } + } -impl<'a, P> fmt::Debug for SplitNInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNInternal") - .field("iter", &self.iter) - .field("count", &self.count) - .finish() - } -} + pub(super) struct $splitn_struct<'a, P: Pattern<'a>> { + pub(super) iter: $inner_iter<'a, P>, + /// The number of splits remaining + pub(super) count: usize, + } -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next() + impl<'a, P> fmt::Debug for $splitn_struct<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct($debug_str) + .field("iter", &self.iter) + .field("count", &self.count) + .finish() } } - } - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next_back() + impl<'a, P: Pattern<'a>> $splitn_struct<'a, P> { + splitn_next!(next); + + #[unstable(feature = "str_split_as_str", issue = "77998")] + #[allow(unused)] // FIXME complete this feature? + fn as_str(&self) -> &'a str { + self.iter.as_str() } } - } - #[inline] - fn as_str(&self) -> &'a str { - self.iter.as_str() + impl<'a, P: Pattern<'a>> $splitn_struct<'a, P> + where + P::Searcher: ReverseSearcher<'a>, + { + splitn_next!(next_back); + } + }; +} + +splitn_internal! { + struct SplitNInternal { + debug: "SplitNInternal", + iter: SplitInternal, } } generate_pattern_iterators! { forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`splitn`]. /// /// [`splitn`]: str::splitn struct SplitN; reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rsplitn`]. /// /// [`rsplitn`]: str::rsplitn struct RSplitN; - stability: - #[stable(feature = "rust1", since = "1.0.0")] internal: SplitNInternal yielding (&'a str); delegate single ended; } +splitn_internal! { + struct SplitNInclusiveInternal { + debug: "SplitNInclusiveInternal", + iter: SplitInclusiveInternal, + } +} + +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_inclusive`]. + /// + /// [`splitn_inclusive`]: str::splitn_inclusive + struct SplitNInclusive; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_inclusive`]. + /// + /// [`rsplitn_inclusive`]: str::rsplitn_inclusive + struct RSplitNInclusive; + internal: + SplitNInclusiveInternal yielding (&'a str); + delegate single ended; +} + +splitn_internal! { + struct SplitNLeftInclusiveInternal { + debug: "SplitNLeftInclusiveInternal", + iter: SplitLeftInclusiveInternal, + } +} + +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_left_inclusive`]. + /// + /// [`splitn_left_inclusive`]: str::splitn_left_inclusive + struct SplitNLeftInclusive; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_left_inclusive`]. + /// + /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive + struct RSplitNLeftInclusive; + internal: + SplitNLeftInclusiveInternal yielding (&'a str); + delegate single ended; +} + impl<'a, P: Pattern<'a>> SplitN<'a, P> { /// Returns remainder of the split string /// @@ -1075,17 +1158,19 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { generate_pattern_iterators! { forward: + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`match_indices`]. /// /// [`match_indices`]: str::match_indices struct MatchIndices; reverse: + #[stable(feature = "str_match_indices", since = "1.5.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rmatch_indices`]. /// /// [`rmatch_indices`]: str::rmatch_indices struct RMatchIndices; - stability: - #[stable(feature = "str_match_indices", since = "1.5.0")] internal: MatchIndicesInternal yielding ((usize, &'a str)); delegate double ended; @@ -1132,17 +1217,19 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { generate_pattern_iterators! { forward: + #[stable(feature = "str_matches", since = "1.2.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`matches`]. /// /// [`matches`]: str::matches struct Matches; reverse: + #[stable(feature = "str_matches", since = "1.2.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] /// Created with the method [`rmatches`]. /// /// [`rmatches`]: str::rmatches struct RMatches; - stability: - #[stable(feature = "str_matches", since = "1.2.0")] internal: MatchesInternal yielding (&'a str); delegate double ended; @@ -1373,56 +1460,6 @@ impl<'a> SplitAsciiWhitespace<'a> { } } -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_inclusive`]: str::split_inclusive -#[stable(feature = "split_inclusive", since = "1.51.0")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next_inclusive() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive").field("0", &self.0).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { - fn clone(&self) -> Self { - SplitInclusive(self.0.clone()) - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator - for SplitInclusive<'a, P> -{ - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back_inclusive() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} - impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { /// Returns remainder of the split string /// @@ -1444,56 +1481,6 @@ impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { } } -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as an initiator -/// of the subslice. -/// -/// This struct is created by the [`split_left_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_left_inclusive`]: str::split_left_inclusive -#[unstable(feature = "split_inclusive_variants", issue = "none")] -pub struct SplitLeftInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, P: Pattern<'a>> Iterator for SplitLeftInclusive<'a, P> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next_left_inclusive() - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitLeftInclusive<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitLeftInclusive").field("0", &self.0).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitLeftInclusive<'a, P> { - fn clone(&self) -> Self { - SplitLeftInclusive(self.0.clone()) - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator - for SplitLeftInclusive<'a, P> -{ - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back_left_inclusive() - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitLeftInclusive<'a, P> {} - impl<'a, P: Pattern<'a>> SplitLeftInclusive<'a, P> { /// Returns remainder of the splitted string /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 441a2733f5d0f..7316504e13854 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,8 +13,8 @@ mod iter; mod traits; mod validations; -use self::pattern::Pattern; -use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; +use self::iter::{SplitInclusiveInternal, SplitLeftInclusiveInternal, SplitTerminatorInternal}; +use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; use crate::mem; @@ -70,7 +70,10 @@ pub use iter::SplitAsciiWhitespace; pub use iter::SplitInclusive; #[unstable(feature = "split_inclusive_variants", issue = "none")] -pub use iter::SplitLeftInclusive; +pub use iter::{ + RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, + SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, +}; #[unstable(feature = "str_internals", issue = "none")] pub use validations::{next_code_point, utf8_char_width}; @@ -1326,13 +1329,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_bookending_empty: true, - finished: false, - }) + Split(SplitInternal::new(self, pat)) } /// An iterator over substrings of this string slice, separated by @@ -1366,13 +1363,7 @@ impl str { #[stable(feature = "split_inclusive", since = "1.51.0")] #[inline] pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { - SplitInclusive(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_bookending_empty: false, - finished: false, - }) + SplitInclusive(SplitInclusiveInternal::new(self, pat)) } /// An iterator over substrings of this string slice, separated by @@ -1408,13 +1399,7 @@ impl str { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] pub fn split_left_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitLeftInclusive<'a, P> { - SplitLeftInclusive(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_bookending_empty: false, - finished: self.is_empty(), - }) + SplitLeftInclusive(SplitLeftInclusiveInternal::new(self, pat)) } /// An iterator over substrings of the given string slice, separated by @@ -1514,7 +1499,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { allow_bookending_empty: false, ..self.split(pat).0 }) + SplitTerminator(SplitTerminatorInternal::new(self, pat)) } /// An iterator over substrings of `self`, separated by characters From 7ab8d4b1d77a372b98776d3bb8e27d7449a6ffbb Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 22 Dec 2021 10:40:29 -0500 Subject: [PATCH 07/10] Implement methods to create new str iterator variants --- library/core/src/slice/mod.rs | 284 +++++++++++------------ library/core/src/str/iter.rs | 92 +++++--- library/core/src/str/mod.rs | 420 +++++++++++++++++++++++++++++++--- 3 files changed, 586 insertions(+), 210 deletions(-) diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index b789e05bd5690..1c5e5617f7ba2 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -1917,6 +1917,68 @@ impl [T] { SplitMut::new(self, pred) } + /// Returns an iterator over subslices separated by elements that match + /// `pred`, starting at the end of the slice and working backwards. + /// The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let slice = [11, 22, 33, 0, 44, 55]; + /// let mut iter = slice.rsplit(|num| *num == 0); + /// + /// assert_eq!(iter.next().unwrap(), &[44, 55]); + /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); + /// assert_eq!(iter.next(), None); + /// ``` + /// + /// As with `split()`, if the first or last element is matched, an empty + /// slice will be the first (or last) item returned by the iterator. + /// + /// ``` + /// let v = &[0, 1, 1, 2, 3, 5, 8]; + /// let mut it = v.rsplit(|n| *n % 2 == 0); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next().unwrap(), &[3, 5]); + /// assert_eq!(it.next().unwrap(), &[1, 1]); + /// assert_eq!(it.next().unwrap(), &[]); + /// assert_eq!(it.next(), None); + /// ``` + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplit::new(self, pred) + } + + /// Returns an iterator over mutable subslices separated by elements that + /// match `pred`, starting at the end of the slice and working + /// backwards. The matched element is not contained in the subslices. + /// + /// # Examples + /// + /// ``` + /// let mut v = [100, 400, 300, 200, 600, 500]; + /// + /// let mut count = 0; + /// for group in v.rsplit_mut(|num| *num % 3 == 0) { + /// count += 1; + /// group[0] = count; + /// } + /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); + /// ``` + /// + #[stable(feature = "slice_rsplit", since = "1.27.0")] + #[inline] + pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + where + F: FnMut(&T) -> bool, + { + RSplitMut::new(self, pred) + } + /// Returns an iterator over subslices separated by elements that match /// `pred`. The matched element is contained in the end of the previous /// subslice as a terminator. @@ -1980,8 +2042,8 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`. The matched element is contained in the start of the following - /// subslice as an initiator. + /// `pred`, in reverse order. The matched element is contained in the end + /// of the previous subslice as a terminator. /// /// # Examples /// @@ -1989,39 +2051,39 @@ impl [T] { /// #![feature(split_inclusive_variants)] /// /// let slice = [10, 40, 33, 20]; - /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[33, 20]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); /// assert!(iter.next().is_none()); /// ``` /// /// If the last element of the slice is matched, - /// that element will be considered the initiator of a new slice. - /// That slice will be the last item returned by the iterator. + /// that element will be considered the terminator of the preceding slice. + /// That slice will be the first item returned by the iterator. /// /// ``` /// #![feature(split_inclusive_variants)] /// /// let slice = [3, 10, 40, 33]; - /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); - /// assert_eq!(iter.next().unwrap(), &[33]); + /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[3]); /// assert!(iter.next().is_none()); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn split_left_inclusive(&self, pred: F) -> SplitLeftInclusive<'_, T, F> + pub fn rsplit_inclusive(&self, pred: F) -> RSplitInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - SplitLeftInclusive::new(self, pred) + RSplitInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`. The matched element is contained in the following - /// subslice as an initiator. + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. /// /// # Examples /// @@ -2030,85 +2092,24 @@ impl [T] { /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// - /// for group in v.split_left_inclusive_mut(|num| *num % 3 == 0) { - /// group[0] = 1; + /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; /// } - /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); + /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn split_left_inclusive_mut(&mut self, pred: F) -> SplitLeftInclusiveMut<'_, T, F> - where - F: FnMut(&T) -> bool, - { - SplitLeftInclusiveMut::new(self, pred) - } - - /// Returns an iterator over subslices separated by elements that match - /// `pred`, starting at the end of the slice and working backwards. - /// The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let slice = [11, 22, 33, 0, 44, 55]; - /// let mut iter = slice.rsplit(|num| *num == 0); - /// - /// assert_eq!(iter.next().unwrap(), &[44, 55]); - /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]); - /// assert_eq!(iter.next(), None); - /// ``` - /// - /// As with `split()`, if the first or last element is matched, an empty - /// slice will be the first (or last) item returned by the iterator. - /// - /// ``` - /// let v = &[0, 1, 1, 2, 3, 5, 8]; - /// let mut it = v.rsplit(|n| *n % 2 == 0); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next().unwrap(), &[3, 5]); - /// assert_eq!(it.next().unwrap(), &[1, 1]); - /// assert_eq!(it.next().unwrap(), &[]); - /// assert_eq!(it.next(), None); - /// ``` - #[stable(feature = "slice_rsplit", since = "1.27.0")] - #[inline] - pub fn rsplit(&self, pred: F) -> RSplit<'_, T, F> - where - F: FnMut(&T) -> bool, - { - RSplit::new(self, pred) - } - - /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, starting at the end of the slice and working - /// backwards. The matched element is not contained in the subslices. - /// - /// # Examples - /// - /// ``` - /// let mut v = [100, 400, 300, 200, 600, 500]; - /// - /// let mut count = 0; - /// for group in v.rsplit_mut(|num| *num % 3 == 0) { - /// count += 1; - /// group[0] = count; - /// } - /// assert_eq!(v, [3, 400, 300, 2, 600, 1]); - /// ``` - /// - #[stable(feature = "slice_rsplit", since = "1.27.0")] - #[inline] - pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut<'_, T, F> + pub fn rsplit_inclusive_mut(&mut self, pred: F) -> RSplitInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitMut::new(self, pred) + RSplitInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match - /// `pred`, in reverse order. The matched element is contained in the end - /// of the previous subslice as a terminator. + /// `pred`. The matched element is contained in the start of the following + /// subslice as an initiator. /// /// # Examples /// @@ -2116,39 +2117,39 @@ impl [T] { /// #![feature(split_inclusive_variants)] /// /// let slice = [10, 40, 33, 20]; - /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20]); /// assert!(iter.next().is_none()); /// ``` /// /// If the last element of the slice is matched, - /// that element will be considered the terminator of the preceding slice. - /// That slice will be the first item returned by the iterator. + /// that element will be considered the initiator of a new slice. + /// That slice will be the last item returned by the iterator. /// /// ``` /// #![feature(split_inclusive_variants)] /// /// let slice = [3, 10, 40, 33]; - /// let mut iter = slice.rsplit_inclusive(|num| num % 3 == 0); + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[10, 40, 33]); - /// assert_eq!(iter.next().unwrap(), &[3]); + /// assert_eq!(iter.next().unwrap(), &[3, 10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33]); /// assert!(iter.next().is_none()); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit_inclusive(&self, pred: F) -> RSplitInclusive<'_, T, F> + pub fn split_left_inclusive(&self, pred: F) -> SplitLeftInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitInclusive::new(self, pred) + SplitLeftInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, in reverse order. The matched element is contained in the - /// previous subslice as a terminator. + /// match `pred`. The matched element is contained in the following + /// subslice as an initiator. /// /// # Examples /// @@ -2157,19 +2158,18 @@ impl [T] { /// /// let mut v = [10, 40, 30, 20, 60, 50]; /// - /// for group in v.split_inclusive_mut(|num| *num % 3 == 0) { - /// let terminator_idx = group.len()-1; - /// group[terminator_idx] = 1; + /// for group in v.split_left_inclusive_mut(|num| *num % 3 == 0) { + /// group[0] = 1; /// } - /// assert_eq!(v, [10, 40, 1, 20, 1, 1]); + /// assert_eq!(v, [1, 40, 1, 20, 1, 50]); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit_inclusive_mut(&mut self, pred: F) -> RSplitInclusiveMut<'_, T, F> + pub fn split_left_inclusive_mut(&mut self, pred: F) -> SplitLeftInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitInclusiveMut::new(self, pred) + SplitLeftInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -2399,112 +2399,112 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`. The matched element is contained in the start of the following - /// subslice as an initiator. + /// `pred`, in reverse order, limited to returning at most `n` items. The + /// matched element is contained in the end of the previous subslice as a + /// terminator. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. /// /// # Examples /// /// ``` /// #![feature(split_inclusive_variants)] /// - /// let slice = [10, 40, 33, 20, 9]; - /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); + /// let slice = [20, 60, 10, 40, 33, 20]; + /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[10, 40]); - /// assert_eq!(iter.next().unwrap(), &[33, 20, 9]); + /// assert_eq!(iter.next().unwrap(), &[20]); + /// assert_eq!(iter.next().unwrap(), &[20, 60, 10, 40, 33]); /// assert!(iter.next().is_none()); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn splitn_left_inclusive(&self, n: usize, pred: F) -> SplitNLeftInclusive<'_, T, F> + pub fn rsplitn_inclusive(&self, n: usize, pred: F) -> RSplitNInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - SplitNLeftInclusive::new(self.split_left_inclusive(pred), n) + RSplitNInclusive::new(self.rsplit_inclusive(pred), n) } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`. The matched element is contained in the following - /// subslice as an initiator. + /// match `pred`, in reverse order. The matched element is contained in the + /// previous subslice as a terminator. /// /// # Examples /// /// ``` /// #![feature(split_inclusive_variants)] /// - /// let mut v = [10, 40, 30, 20, 60, 50, 90]; + /// let mut v = [10, 40, 30, 20, 60, 50]; /// - /// for group in v.splitn_left_inclusive_mut(2, |num| *num % 3 == 0) { - /// group[0] = 1; + /// for group in v.rsplitn_inclusive_mut(2, |num| *num % 3 == 0) { + /// let terminator_idx = group.len()-1; + /// group[terminator_idx] = 1; /// } - /// assert_eq!(v, [1, 40, 1, 20, 60, 50, 90]); + /// assert_eq!(v, [10, 40, 30, 20, 1, 1]); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn splitn_left_inclusive_mut( - &mut self, - n: usize, - pred: F, - ) -> SplitNLeftInclusiveMut<'_, T, F> + pub fn rsplitn_inclusive_mut(&mut self, n: usize, pred: F) -> RSplitNInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool, { - SplitNLeftInclusiveMut::new(self.split_left_inclusive_mut(pred), n) + RSplitNInclusiveMut::new(self.rsplit_inclusive_mut(pred), n) } /// Returns an iterator over subslices separated by elements that match - /// `pred`, in reverse order, limited to returning at most `n` items. The - /// matched element is contained in the end of the previous subslice as a - /// terminator. - /// - /// The last element returned, if any, will contain the remainder of the - /// slice. + /// `pred`. The matched element is contained in the start of the following + /// subslice as an initiator. /// /// # Examples /// /// ``` /// #![feature(split_inclusive_variants)] /// - /// let slice = [20, 60, 10, 40, 33, 20]; - /// let mut iter = slice.rsplitn_inclusive(2, |num| num % 3 == 0); + /// let slice = [10, 40, 33, 20, 9]; + /// let mut iter = slice.splitn_left_inclusive(2, |num| num % 3 == 0); /// - /// assert_eq!(iter.next().unwrap(), &[20]); - /// assert_eq!(iter.next().unwrap(), &[20, 60, 10, 40, 33]); + /// assert_eq!(iter.next().unwrap(), &[10, 40]); + /// assert_eq!(iter.next().unwrap(), &[33, 20, 9]); /// assert!(iter.next().is_none()); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplitn_inclusive(&self, n: usize, pred: F) -> RSplitNInclusive<'_, T, F> + pub fn splitn_left_inclusive(&self, n: usize, pred: F) -> SplitNLeftInclusive<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitNInclusive::new(self.rsplit_inclusive(pred), n) + SplitNLeftInclusive::new(self.split_left_inclusive(pred), n) } /// Returns an iterator over mutable subslices separated by elements that - /// match `pred`, in reverse order. The matched element is contained in the - /// previous subslice as a terminator. + /// match `pred`. The matched element is contained in the following + /// subslice as an initiator. /// /// # Examples /// /// ``` /// #![feature(split_inclusive_variants)] /// - /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let mut v = [10, 40, 30, 20, 60, 50, 90]; /// - /// for group in v.rsplitn_inclusive_mut(2, |num| *num % 3 == 0) { - /// let terminator_idx = group.len()-1; - /// group[terminator_idx] = 1; + /// for group in v.splitn_left_inclusive_mut(2, |num| *num % 3 == 0) { + /// group[0] = 1; /// } - /// assert_eq!(v, [10, 40, 30, 20, 1, 1]); + /// assert_eq!(v, [1, 40, 1, 20, 60, 50, 90]); /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplitn_inclusive_mut(&mut self, n: usize, pred: F) -> RSplitNInclusiveMut<'_, T, F> + pub fn splitn_left_inclusive_mut( + &mut self, + n: usize, + pred: F, + ) -> SplitNLeftInclusiveMut<'_, T, F> where F: FnMut(&T) -> bool, { - RSplitNInclusiveMut::new(self.rsplit_inclusive_mut(pred), n) + SplitNLeftInclusiveMut::new(self.split_left_inclusive_mut(pred), n) } /// Returns an iterator over subslices separated by elements that match diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index a105b954f82c8..101d578bca366 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -565,6 +565,19 @@ macro_rules! generate_pattern_iterators { } => {} } +// Making this a trait suppresses some `unused` lints +trait SplitIterInternal<'a, P: Pattern<'a>> { + fn next(&mut self) -> Option<&'a str>; + + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>; + + fn get_end(&mut self) -> Option<&'a str>; + + fn as_str(&self) -> &'a str; +} + macro_rules! split_internal { ( $split_struct:ident { @@ -573,7 +586,6 @@ macro_rules! split_internal { $(skip_trailing_empty: $skip_trailing_empty:ident,)? include_leading: $include_leading:literal, include_trailing: $include_trailing:literal, - $(get_end: $get_end:ident,)? } ) => { pub(super) struct $split_struct<'a, P: Pattern<'a>> { @@ -618,7 +630,9 @@ macro_rules! split_internal { $($skip_trailing_empty: true,)? } } + } + impl<'a, P: Pattern<'a>> SplitIterInternal<'a, P> for $split_struct<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { if self.finished { @@ -696,22 +710,26 @@ macro_rules! split_internal { } } - $( - #[inline] - fn $get_end(&mut self) -> Option<&'a str> { - if self.finished { + #[inline] + fn get_end(&mut self) -> Option<&'a str> { + if self.finished { + None + } else { + self.finished = true; + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + let end = unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }; + if (false + $(|| self.$skip_leading_empty)? + $(|| self.$skip_trailing_empty)? + ) && end == "" { None } else { - self.finished = true; - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - Some(unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) }) + Some(end) } } - )? + } #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - #[allow(unused)] // FIXME complete this feature fn as_str(&self) -> &'a str { // `Self::get_end` doesn't change `self.start` if self.finished { @@ -730,7 +748,6 @@ split_internal! { debug: "SplitInternal", include_leading: false, include_trailing: false, - get_end: get_end, } } @@ -802,7 +819,6 @@ split_internal! { skip_trailing_empty: skip_trailing_empty, include_leading: false, include_trailing: true, - get_end: get_end, } } @@ -833,7 +849,6 @@ split_internal! { skip_leading_empty: skip_leading_empty, include_leading: true, include_trailing: false, - get_end: get_end, } } @@ -928,25 +943,6 @@ impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { } } -macro_rules! splitn_next { - ($($fn:ident),*) => {$( - #[inline] - fn $fn(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.$fn() - } - } - } - )*}; -} - macro_rules! splitn_internal { ( struct $splitn_struct:ident { @@ -978,7 +974,20 @@ macro_rules! splitn_internal { } impl<'a, P: Pattern<'a>> $splitn_struct<'a, P> { - splitn_next!(next); + #[inline] + fn next(&mut self) -> Option<&'a str> { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } #[unstable(feature = "str_split_as_str", issue = "77998")] #[allow(unused)] // FIXME complete this feature? @@ -991,7 +1000,20 @@ macro_rules! splitn_internal { where P::Searcher: ReverseSearcher<'a>, { - splitn_next!(next_back); + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next_back() + } + } + } } }; } diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 7316504e13854..aaa6c5e288b51 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -13,7 +13,10 @@ mod iter; mod traits; mod validations; -use self::iter::{SplitInclusiveInternal, SplitLeftInclusiveInternal, SplitTerminatorInternal}; +use self::iter::{ + SplitInclusiveInternal, SplitLeftInclusiveInternal, SplitNInclusiveInternal, + SplitNLeftInclusiveInternal, SplitTerminatorInternal, +}; use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; use crate::char::{self, EscapeDebugExtArgs}; @@ -1332,6 +1335,58 @@ impl str { Split(SplitInternal::new(self, pat)) } + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern and yielded in reverse order. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a reverse + /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split`] method can be used. + /// + /// [`split`]: str::split + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); + /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); + /// + /// let v: Vec<&str> = "".rsplit('X').collect(); + /// assert_eq!(v, [""]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); + /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); + /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "def", "abc"]); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplit(self.split(pat).0) + } + /// An iterator over substrings of this string slice, separated by /// characters matched by a pattern. Differs from the iterator produced by /// `split` in that `split_inclusive` leaves the matched part as the @@ -1360,12 +1415,63 @@ impl str { /// .split_inclusive('\n').collect(); /// assert_eq!(v, ["Mary had a little lamb\n", "little lamb\n", "little lamb.\n"]); /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// let v: Vec<&str> = "".split_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` #[stable(feature = "split_inclusive", since = "1.51.0")] #[inline] pub fn split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P> { SplitInclusive(SplitInclusiveInternal::new(self, pat)) } + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern and yielded in reverse order. Differs + /// from the iterator produced by `rsplit` in that `rsplit_inclusive` leaves + /// the matched part as the terminator of the substring. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .rsplit_inclusive('\n').collect(); + /// assert_eq!(v, ["little lamb.", "little lamb\n", "Mary had a little lamb\n"]); + /// ``` + /// + /// If the last element of the string is matched, + /// that element will be considered the terminator of the preceding substring. + /// That substring will be the first item returned by the iterator. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .rsplit_inclusive('\n').collect(); + /// assert_eq!(v, ["little lamb.\n", "little lamb\n", "Mary had a little lamb\n"]); + /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "".rsplit_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitInclusive<'a, P> { + RSplitInclusive(self.split_inclusive(pat).0) + } + /// An iterator over substrings of this string slice, separated by /// characters matched by a pattern. Differs from the iterator produced by /// `split` in that `split_left_inclusive` leaves the matched part as the @@ -1396,14 +1502,24 @@ impl str { /// .split_left_inclusive('\n').collect(); /// assert_eq!(v, ["\nMary had a little lamb", "\nlittle lamb", "\nlittle lamb.", "\n"]); /// ``` + /// + /// If the string is empty, the iterator returns [`None`]. + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "".split_left_inclusive('\n').collect(); + /// assert_eq!(v.len(), 0); + /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] pub fn split_left_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitLeftInclusive<'a, P> { SplitLeftInclusive(SplitLeftInclusiveInternal::new(self, pat)) } - /// An iterator over substrings of the given string slice, separated by - /// characters matched by a pattern and yielded in reverse order. + /// An iterator over substrings of this string slice, separated by + /// characters matched by a pattern and yielded in reverse order. Differs + /// from the iterator produced by `rsplit` in that `rsplit_left_inclusive` + /// leaves the matched part as the initiator of the substring. /// /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a /// function or closure that determines if a character matches. @@ -1411,47 +1527,40 @@ impl str { /// [`char`]: prim@char /// [pattern]: self::pattern /// - /// # Iterator behavior - /// - /// The returned iterator requires that the pattern supports a reverse - /// search, and it will be a [`DoubleEndedIterator`] if a forward/reverse - /// search yields the same elements. - /// - /// For iterating from the front, the [`split`] method can be used. - /// - /// [`split`]: str::split - /// /// # Examples /// - /// Simple patterns: - /// /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplit(' ').collect(); - /// assert_eq!(v, ["lamb", "little", "a", "had", "Mary"]); - /// - /// let v: Vec<&str> = "".rsplit('X').collect(); - /// assert_eq!(v, [""]); + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." + /// .rsplit_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\nlittle lamb.", "\nlittle lamb", "Mary had a little lamb"]); + /// ``` /// - /// let v: Vec<&str> = "lionXXtigerXleopard".rsplit('X').collect(); - /// assert_eq!(v, ["leopard", "tiger", "", "lion"]); + /// If the last element of the string is matched, + /// that element will be considered the terminator of the preceding substring. + /// That substring will be the first item returned by the iterator. /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplit("::").collect(); - /// assert_eq!(v, ["leopard", "tiger", "lion"]); + /// ``` + /// #![feature(split_inclusive_variants)] + /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" + /// .rsplit_left_inclusive('\n').collect(); + /// assert_eq!(v, ["\n", "\nlittle lamb.", "\nlittle lamb", "\nMary had a little lamb"]); /// ``` /// - /// A more complex pattern, using a closure: + /// If the string is empty, the iterator returns [`None`]. /// /// ``` - /// let v: Vec<&str> = "abc1defXghi".rsplit(|c| c == '1' || c == 'X').collect(); - /// assert_eq!(v, ["ghi", "def", "abc"]); + /// #![feature(split_inclusive_variants)] + /// let o = "".rsplit_left_inclusive('\n').next(); + /// assert_eq!(o, None); /// ``` - #[stable(feature = "rust1", since = "1.0.0")] + #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P> - where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, - { - RSplit(self.split(pat).0) + pub fn rsplit_left_inclusive<'a, P: Pattern<'a>>( + &'a self, + pat: P, + ) -> RSplitLeftInclusive<'a, P> { + RSplitLeftInclusive(self.split_left_inclusive(pat).0) } /// An iterator over substrings of the given string slice, separated by @@ -1655,6 +1764,251 @@ impl str { RSplitN(self.splitn(n, pat).0) } + /// An iterator over substrings of the given string slice, separated by a + /// pattern, leaving the matched part as the terminator of the substring, + /// restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn_inclusive`] method can be + /// used. + /// + /// [`rsplitn_inclusive`]: str::rsplitn_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lambda".splitn_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["Mary ", "had ", "a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn_inclusive(3, "X").collect(); + /// assert_eq!(v, ["lionX", "X", "tigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn_inclusive(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".splitn_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc1", "defXghi"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_inclusive<'a, P: Pattern<'a>>( + &'a self, + n: usize, + pat: P, + ) -> SplitNInclusive<'a, P> { + SplitNInclusive(SplitNInclusiveInternal { iter: self.split_inclusive(pat).0, count: n }) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, leaving the matched part + /// as the terminator of the substring, restricted to returning at most `n` + /// items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn_inclusive`] method can be used. + /// + /// [`splitn_inclusive`]: str::splitn_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["lamb", "little ", "Mary had a "]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn_inclusive(3, 'X').collect(); + /// assert_eq!(v, ["leopard", "tigerX", "lionXX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn_inclusive(2, "::").collect(); + /// assert_eq!(v, ["leopard", "lion::tiger::"]); + /// + /// let v: Vec<&str> = "".rsplitn_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".rsplitn_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["ghi", "abc1defX"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_inclusive<'a, P>(&'a self, n: usize, pat: P) -> RSplitNInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitNInclusive(self.splitn_inclusive(n, pat).0) + } + + /// An iterator over substrings of the given string slice, separated by a + /// pattern, leaving the matched part as the initiator of the substring, + /// restricted to returning at most `n` items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is + /// not efficient to support. + /// + /// If the pattern allows a reverse search, the [`rsplitn_left_inclusive`] method can be + /// used. + /// + /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lambda".splitn_left_inclusive(3, ' ').collect(); + /// assert_eq!(v, ["Mary", " had", " a little lambda"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".splitn_left_inclusive(3, "X").collect(); + /// assert_eq!(v, ["lion", "X", "XtigerXleopard"]); + /// + /// let v: Vec<&str> = "abcXdef".splitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v, ["abcXdef"]); + /// + /// let v: Vec<&str> = "".splitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".splitn_left_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["abc", "1defXghi"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn splitn_left_inclusive<'a, P: Pattern<'a>>( + &'a self, + n: usize, + pat: P, + ) -> SplitNLeftInclusive<'a, P> { + SplitNLeftInclusive(SplitNLeftInclusiveInternal { + iter: self.split_left_inclusive(pat).0, + count: n, + }) + } + + /// An iterator over substrings of this string slice, separated by a + /// pattern, starting from the end of the string, leaving the matched part + /// as the terminator of the substring, restricted to returning at most `n` + /// items. + /// + /// If `n` substrings are returned, the last substring (the `n`th substring) + /// will contain the remainder of the string. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// # Iterator behavior + /// + /// The returned iterator will not be double ended, because it is not + /// efficient to support. + /// + /// For splitting from the front, the [`splitn_left_inclusive`] method can be used. + /// + /// [`splitn_left_inclusive`]: str::splitn_left_inclusive + /// + /// # Examples + /// + /// Simple patterns: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn_left_inclusive(3, ' ').collect(); + /// assert_eq!(v, [" lamb", " little", "Mary had a"]); + /// + /// let v: Vec<&str> = "lionXXtigerXleopard".rsplitn_left_inclusive(3, 'X').collect(); + /// assert_eq!(v, ["Xleopard", "Xtiger", "lionX"]); + /// + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn_left_inclusive(2, "::").collect(); + /// assert_eq!(v, ["::leopard", "lion::tiger"]); + /// + /// let v: Vec<&str> = "".rsplitn_left_inclusive(1, 'X').collect(); + /// assert_eq!(v.len(), 0); + /// ``` + /// + /// A more complex pattern, using a closure: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = "abc1defXghi".rsplitn_left_inclusive(2, |c| c == '1' || c == 'X').collect(); + /// assert_eq!(v, ["Xghi", "abc1def"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplitn_left_inclusive<'a, P>(&'a self, n: usize, pat: P) -> RSplitNLeftInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitNLeftInclusive(self.splitn_left_inclusive(n, pat).0) + } + /// Splits the string on the first occurrence of the specified delimiter and /// returns prefix before delimiter and suffix after delimiter. /// From a76b09c87e1bd1690886981901359f9ec665e135 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 22 Dec 2021 21:15:51 -0500 Subject: [PATCH 08/10] Consolidate slice iter impls into macro --- library/alloc/tests/slice.rs | 13 +- library/core/src/slice/iter.rs | 1004 +++++-------------------- library/core/src/slice/iter/macros.rs | 300 +++++++- library/core/src/str/iter.rs | 11 +- 4 files changed, 484 insertions(+), 844 deletions(-) diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index d55d53be7bc30..f9b46cfc3ceb0 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1236,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, @@ -1267,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 @@ -1279,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"); diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 5b2f32bc56ca4..216e465637b2d 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -374,838 +374,186 @@ pub(super) trait SplitIter: DoubleEndedIterator { fn finish(&mut self) -> Option; } -/// An iterator over subslices separated by elements that match a predicate -/// function. -/// -/// This struct is created by the [`split`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 33, 20]; -/// let mut iter = slice.split(|num| num % 3 == 0); -/// ``` -/// -/// [`split`]: slice::split -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Split<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods - pub(crate) v: &'a [T], - pred: P, - // Used for `SplitAsciiWhitespace` `as_str` method - pub(crate) finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } - } - /// Returns a slice which contains items not yet handled by split. - /// # Example - /// - /// ``` - /// #![feature(split_as_slice)] - /// let slice = [1,2,3,4,5]; - /// let mut split = slice.split(|v| v % 2 == 0); - /// assert!(split.next().is_some()); - /// assert_eq!(split.as_slice(), &[3,4,5]); - /// ``` - #[unstable(feature = "split_as_slice", issue = "96137")] - pub fn as_slice(&self) -> &'a [T] { - if self.finished { &[] } else { &self.v } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Split<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Split<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - Split { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().position(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx + 1..]; - ret - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len() + 1` empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().rposition(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[idx + 1..]); - self.v = &self.v[..idx]; - ret - } - } - } -} - -impl<'a, T, P> SplitIter for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let slice = [10, 40, 33, 20]; -/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); -/// ``` -/// -/// [`split_inclusive`]: slice::split_inclusive -/// [slices]: slice -#[stable(feature = "split_inclusive", since = "1.51.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl fmt::Debug for SplitInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl Clone for SplitInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = - self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; - let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -impl<'a, T, P> SplitIter for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as an initiator -/// of the subslice. -/// -/// This struct is created by the [`split_left_inclusive`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// #![feature(split_inclusive_variants)] -/// -/// let slice = [10, 40, 33, 20]; -/// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); -/// ``` -/// -/// [`split_left_inclusive`]: slice::split_left_inclusive -/// [slices]: slice -#[unstable(feature = "split_inclusive_variants", issue = "none")] -pub struct SplitLeftInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusive<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl fmt::Debug for SplitLeftInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitLeftInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl Clone for SplitLeftInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitLeftInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, T, P> Iterator for SplitLeftInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The first index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the right. - let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] }; - let idx = - remainder.iter().position(|x| (self.pred)(x)).map(|x| x + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = self.v.iter().rposition(|x| (self.pred)(x)).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl FusedIterator for SplitLeftInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -impl<'a, T, P> SplitIter for SplitLeftInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. -/// -/// This struct is created by the [`split_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut v = [10, 40, 30, 20, 60, 50]; -/// let iter = v.split_mut(|num| *num % 3 == 0); -/// ``` -/// -/// [`split_mut`]: slice::split_mut -/// [slices]: slice -#[stable(feature = "rust1", since = "1.0.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - Self { v: slice, pred, finished: false } - } -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -impl<'a, T, P> SplitIter for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = &mut tail[1..]; - Some(head) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len() + 1` empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().rposition(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(&mut tail[1..]) - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the ends of the subslices. -/// -/// This struct is created by the [`split_inclusive_mut`] method on [slices]. -/// -/// # Example -/// -/// ``` -/// let mut v = [10, 40, 30, 20, 60, 50]; -/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); -/// ``` -/// -/// [`split_inclusive_mut`]: slice::split_inclusive_mut -/// [slices]: slice -#[stable(feature = "split_inclusive", since = "1.51.0")] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct SplitInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl fmt::Debug for SplitInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } - } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowck limitations - let pred = &mut self.pred; - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = &self.v[..(self.v.len() - 1)]; - remainder.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) +split_iter! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. + /// + /// This struct is created by the [`split`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split(|num| num % 3 == 0); + /// ``` + /// + /// [`split`]: slice::split + /// [slices]: slice + struct Split { + #[stable(feature = "core_impl_debug", since = "1.9.0")] + debug: "Split", + include_leading: false, + include_trailing: false, } -} - -#[stable(feature = "split_inclusive", since = "1.51.0")] -impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} -impl<'a, T, P> SplitIter for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } + /// Returns a slice which contains items not yet handled by split. + /// # Example + /// + /// ``` + /// #![feature(split_as_slice)] + /// let slice = [1,2,3,4,5]; + /// let mut split = slice.split(|v| v % 2 == 0); + /// assert!(split.next().is_some()); + /// assert_eq!(split.as_slice(), &[3,4,5]); + /// ``` + #[unstable(feature = "split_as_slice", issue = "96137")] + pub fn as_slice(&self) -> &'a [T] { + if self.finished { &[] } else { &self.v } } } -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the beginnings of the subslices. -/// -/// This struct is created by the [`split_left_inclusive_mut`] method on -/// [slices]. -/// -/// # Example -/// -/// ``` -/// #![feature(split_inclusive_variants)] -/// -/// let mut v = [10, 40, 30, 20, 60, 50]; -/// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0); -/// ``` -/// -/// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut -/// [slices]: slice -#[unstable(feature = "split_inclusive_variants", issue = "none")] -pub struct SplitLeftInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitLeftInclusiveMut<'a, T, P> { - #[inline] - pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { - let finished = slice.is_empty(); - Self { v: slice, pred, finished } +split_iter! { + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. + /// + /// This struct is created by the [`split_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_mut`]: slice::split_mut + /// [slices]: slice + struct SplitMut { + #[stable(feature = "core_impl_debug", since = "1.9.0")] + debug: "SplitMut", + include_leading: false, + include_trailing: false, } } -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl fmt::Debug for SplitLeftInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitLeftInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() +split_iter! { + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. Unlike `Split`, it contains the matched part as a terminator + /// of the subslice. + /// + /// This struct is created by the [`split_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`split_inclusive`]: slice::split_inclusive + /// [slices]: slice + struct SplitInclusive { + #[stable(feature = "split_inclusive", since = "1.51.0")] + debug: "SplitInclusive", + include_leading: false, + include_trailing: true, } } -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, T, P> Iterator for SplitLeftInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - - // The first index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the right. - let remainder = if self.v.is_empty() { &[] } else { &self.v[1..] }; - remainder.iter().position(|x| (*pred)(x)).map(|x| x + 1) - }; - let idx = idx_opt.unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // If the predicate doesn't match anything, we yield one slice. - // If it matches every element, we yield `len()` one-element slices, - // or a single empty slice. - (1, Some(cmp::max(1, self.v.len()))) - } +split_iter! { + #[stable(feature = "split_inclusive", since = "1.51.0")] + #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. Unlike `SplitMut`, it contains the matched + /// parts in the ends of the subslices. + /// + /// This struct is created by the [`split_inclusive_mut`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_inclusive_mut`]: slice::split_inclusive_mut + /// [slices]: slice + struct SplitInclusiveMut { + #[stable(feature = "split_inclusive", since = "1.51.0")] + debug: "SplitInclusiveMut", + include_leading: false, + include_trailing: true, } } -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl<'a, T, P> DoubleEndedIterator for SplitLeftInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowsck limitations - let pred = &mut self.pred; - - self.v.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) +split_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over subslices separated by elements that match a predicate + /// function. Unlike `Split`, it contains the matched part as an initiator + /// of the subslice. + /// + /// This struct is created by the [`split_left_inclusive`] method on [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let slice = [10, 40, 33, 20]; + /// let mut iter = slice.split_left_inclusive(|num| num % 3 == 0); + /// ``` + /// + /// [`split_left_inclusive`]: slice::split_left_inclusive + /// [slices]: slice + struct SplitLeftInclusive { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + debug: "SplitLeftInclusive", + include_leading: true, + include_trailing: false, } } -impl<'a, T, P> SplitIter for SplitLeftInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } +split_iter! { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + #[must_use = "iterators are lazy and do nothing unless consumed"] + /// An iterator over the mutable subslices of the vector which are separated + /// by elements that match `pred`. Unlike `SplitMut`, it contains the matched + /// parts in the beginnings of the subslices. + /// + /// This struct is created by the [`split_left_inclusive_mut`] method on + /// [slices]. + /// + /// # Example + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let mut v = [10, 40, 30, 20, 60, 50]; + /// let iter = v.split_left_inclusive_mut(|num| *num % 3 == 0); + /// ``` + /// + /// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut + /// [slices]: slice + struct SplitLeftInclusiveMut { + #[unstable(feature = "split_inclusive_variants", issue = "none")] + debug: "SplitLeftInclusiveMut", + include_leading: true, + include_trailing: false, } } -#[unstable(feature = "split_inclusive_variants", issue = "none")] -impl FusedIterator for SplitLeftInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - reverse_iter! { #[stable(feature = "slice_rsplit", since = "1.27.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1224,7 +572,9 @@ reverse_iter! { /// [`rsplit`]: slice::rsplit /// [slices]: slice pub struct RSplit { "RSplit"; Split }: Clone +} +reverse_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over subslices separated by elements that match a predicate @@ -1245,7 +595,9 @@ reverse_iter! { /// [`rsplit_left_inclusive`]: slice::rsplit_inclusive /// [slices]: slice pub struct RSplitInclusive { "RSplitInclusive"; SplitInclusive }: Clone +} +reverse_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over subslices separated by elements that match a predicate @@ -1266,7 +618,9 @@ reverse_iter! { /// [`rsplit_left_inclusive`]: slice::rsplit_left_inclusive /// [slices]: slice pub struct RSplitLeftInclusive { "RSplitLeftInclusive"; SplitLeftInclusive }: Clone +} +reverse_iter! { #[stable(feature = "slice_rsplit", since = "1.27.0")] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the subslices of the vector which are separated @@ -1284,7 +638,9 @@ reverse_iter! { /// [`rsplit_mut`]: slice::rsplit_mut /// [slices]: slice pub struct RSplitMut { "RSplitMut"; SplitMut } +} +reverse_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the mutable subslices of the vector which are separated @@ -1305,7 +661,9 @@ reverse_iter! { /// [`rsplit_inclusive_mut`]: slice::rsplit_inclusive_mut /// [slices]: slice pub struct RSplitInclusiveMut { "RSplitInclusiveMut" ; SplitInclusiveMut } +} +reverse_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the mutable subslices of the vector which are separated @@ -1384,7 +742,9 @@ iter_n! { /// [`splitn`]: slice::splitn /// [slices]: slice pub struct SplitN {"SplitN"; Split }: Clone +} +iter_n! { #[stable(feature = "rust1", since = "1.0.0")] #[fused(stable(feature = "fused", since = "1.26.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1404,7 +764,9 @@ iter_n! { /// [`rsplitn`]: slice::rsplitn /// [slices]: slice pub struct RSplitN {"RSplitN"; RSplit }: Clone +} +iter_n! { #[stable(feature = "rust1", since = "1.0.0")] #[fused(stable(feature = "fused", since = "1.26.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1423,7 +785,9 @@ iter_n! { /// [`splitn_mut`]: slice::splitn_mut /// [slices]: slice pub struct SplitNMut {"SplitNMut"; SplitMut } +} +iter_n! { #[stable(feature = "rust1", since = "1.0.0")] #[fused(stable(feature = "fused", since = "1.26.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1443,7 +807,9 @@ iter_n! { /// [`rsplitn_mut`]: slice::rsplitn_mut /// [slices]: slice pub struct RSplitNMut {"RSplitNMut"; RSplitMut } +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1465,7 +831,9 @@ iter_n! { /// [`splitn_inclusive`]: slice::splitn_inclusive /// [slices]: slice pub struct SplitNInclusive {"SplitNInclusive"; SplitInclusive}: Clone +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1487,7 +855,9 @@ iter_n! { /// [`splitn_left_inclusive`]: slice::splitn_left_inclusive /// [slices]: slice pub struct SplitNLeftInclusive {"SplitNLeftInclusive"; SplitLeftInclusive}: Clone +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1509,7 +879,9 @@ iter_n! { /// [`rsplitn_inclusive`]: slice::rsplitn_inclusive /// [slices]: slice pub struct RSplitNInclusive {"RSplitNInclusive"; RSplitInclusive}: Clone +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1531,7 +903,9 @@ iter_n! { /// [`rsplitn_left_inclusive`]: slice::rsplitn_left_inclusive /// [slices]: slice pub struct RSplitNLeftInclusive {"RSplitNLeftInclusive"; RSplitLeftInclusive}: Clone +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1553,7 +927,9 @@ iter_n! { /// [`splitn_inclusive_mut`]: slice::splitn_inclusive_mut /// [slices]: slice pub struct SplitNInclusiveMut {"SplitNInclusiveMut"; SplitInclusiveMut} +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1575,7 +951,9 @@ iter_n! { /// [`splitn_left_inclusive_mut`]: slice::splitn_left_inclusive_mut /// [slices]: slice pub struct SplitNLeftInclusiveMut {"SplitNLeftInclusiveMut"; SplitLeftInclusiveMut} +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] @@ -1597,7 +975,9 @@ iter_n! { /// [`rsplitn_inclusive_mut`]: slice::rsplitn_inclusive_mut /// [slices]: slice pub struct RSplitNInclusiveMut {"RSplitNInclusiveMut"; RSplitInclusiveMut} +} +iter_n! { #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index e022badf68cbb..2ea91ad9759e2 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -397,14 +397,272 @@ macro_rules! iterator { } } +macro_rules! split_iter { + ( + #[$stability:meta] + #[fused($fused_stability:meta)] + $(#[$outer:meta])* + struct $split_iter:ident< + $(shared_ref: & $lt:lifetime)? + $(mut_ref: & $m_lt:lifetime)? + > { + #[$debug_stability:meta] + debug: $debug_name:literal, + include_leading: $include_leading:literal, + include_trailing: $include_trailing:literal, + } + ) => { + $(#[$outer])* + #[$stability] + pub struct $split_iter<$($lt)? $($m_lt)?, T: $($lt)? $($m_lt)?, P> + where + P: FnMut(&T) -> bool, + { + // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods + pub(crate) v: &$($lt)?$($m_lt mut)? [T], + pred: P, + // Used for `SplitAsciiWhitespace` `as_str` method + pub(crate) finished: bool, + } + + impl<$($lt)?$($m_lt)?, T: $($lt)?$($m_lt)?, P: FnMut(&T) -> bool> $split_iter<$($lt)?$($m_lt)?, T, P> { + #[inline] + pub(super) fn new(slice: &$($lt)?$($m_lt mut)? [T], pred: P) -> Self { + Self { + v: slice, + pred, + finished: false, + } + } + } + + #[$debug_stability] + impl fmt::Debug for $split_iter<'_, T, P> + where + P: FnMut(&T) -> bool, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct($debug_name) + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } + } + + split_iter! { + #[$stability] + impl Clone for $split_iter<$(shared_ref: &$lt)? $(mut_ref: &$m_lt)?> {} + } + + #[$stability] + impl<$($lt)?$($m_lt)?, T, P> Iterator for $split_iter<$($lt)?$($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + type Item = &$($lt)?$($m_lt mut)? [T]; + + #[inline] + fn next(&mut self) -> Option { + if self.finished { + return None; + } + + if $include_leading && self.v.is_empty() { + self.finished = true; + return None; + } + + let offset = if $include_leading { + // The first index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the right. + 1 + } else { + 0 + }; + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v[offset..].iter().position(|x| (*pred)(x)).map(|i| i + offset) + }; + + match idx_opt { + None => { + self.finished = true; + if $include_trailing && self.v.is_empty() { + return None; + } + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + Some(ret) + }, + Some(idx) => { + // For shared ref iters + $( + let ret_end = if $include_trailing { idx + 1 } else { idx }; + let ret: &$lt [T] = &self.v[..ret_end]; + let v_start = if $include_leading { idx } else { idx + 1 }; + self.v = &self.v[v_start..]; + Some(ret) + )? + + // For mut ref iters + $( + // Assert that include_leading and include_trailing are not both true + const _: [(); 0 - !{ const A: bool = !($include_leading && $include_trailing); A } as usize] = []; + let tmp: &$m_lt mut [T] = mem::replace(&mut self.v, &mut []); + let split_idx = if $include_trailing { idx + 1 } else { idx }; + let (head, tail) = tmp.split_at_mut(split_idx); + let tail_start = if ($include_leading ^ $include_trailing) { 0 } else { 1 }; + self.v = &mut tail[tail_start..]; + Some(head) + )? + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // If the predicate doesn't match anything, we yield one slice + // for exclusive iterators, and zero for inclusive ones. + // If it matches every element, we yield `len() + 1` empty slices. + let min = if $include_leading || $include_trailing { 0 } else { 1 }; + (min, Some(self.v.len() + min)) + } + } + } + + #[$stability] + impl<$($lt)?$($m_lt)?, T, P> DoubleEndedIterator for $split_iter<$($lt)?$($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn next_back(&mut self) -> Option<::Item> { + if self.finished { + return None; + } + + if $include_trailing && self.v.is_empty() { + self.finished = true; + return None; + } + + let offset = if $include_trailing { + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + 1 + } else { + 0 + }; + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v[..(self.v.len() - offset)].iter().rposition(|x| (*pred)(x)) + }; + + match idx_opt { + None => { + self.finished = true; + if $include_leading && self.v.is_empty() { + return None; + } + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + Some(ret) + }, + Some(idx) => { + // For shared ref iters + $( + let ret_start = if $include_leading { idx } else { idx + 1 }; + let ret: &$lt [T] = &self.v[ret_start..]; + let v_end = if $include_trailing { idx + 1 } else { idx }; + self.v = &self.v[..v_end]; + Some(ret) + )? + + // For mut ref iters + $( + // Assert that include_leading and include_trailing are not both true + const _: [(); 0 - !{ const A: bool = !($include_leading && $include_trailing); A } as usize] = []; + let tmp: &$m_lt mut [T] = mem::replace(&mut self.v, &mut []); + let split_idx = if $include_trailing { idx + 1 } else { idx }; + let (head, tail) = tmp.split_at_mut(split_idx); + let tail_start = if ($include_leading ^ $include_trailing) { 0 } else { 1 }; + self.v = head; + let ret = &mut tail[tail_start..]; + Some(ret) + )? + } + } + } + } + + impl<$($lt)? $($m_lt)?, T, P> SplitIter for $split_iter<$($lt)? $($m_lt)?, T, P> + where + P: FnMut(&T) -> bool, + { + #[inline] + fn finish(&mut self) -> Option<::Item> { + if self.finished { + None + } else { + self.finished = true; + $(let ret: & $lt [T] = self.v;)? + $(let ret: & $m_lt mut [T] = mem::replace(&mut self.v, &mut []);)? + if ($include_leading || $include_trailing) && ret.is_empty() { + None + } else { + Some(ret) + } + } + } + } + + #[$fused_stability] + impl FusedIterator for $split_iter<'_, T, P> where P: FnMut(&T) -> bool {} + }; + + ( + #[$stability:meta] + impl Clone for $split_iter:ident {} + ) => { + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` + #[$stability] + impl<$lt, T, P> Clone for $split_iter<$lt, T, P> + where + P: Clone + FnMut(&T) -> bool, + { + fn clone(&self) -> Self { + Self { + v: self.v, + pred: self.pred.clone(), + finished: self.finished + } + } + } + }; + + ( + #[$stability:meta] + impl Clone for $split_iter:ident {} + ) => {}; +} + macro_rules! reverse_iter { - ($( - #[$stablility:meta] + ( + #[$stability:meta] $(#[$outer:meta])* $vis:vis struct $rev:ident { $str:literal ; $inner:ident } $(: $clone:ident)? - )*) => {$( + ) => { $(#[$outer])* - #[$stablility] + #[$stability] $vis struct $rev<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -419,7 +677,7 @@ macro_rules! reverse_iter { } } - #[$stablility] + #[$stability] impl fmt::Debug for $rev<'_, T, P> where P: FnMut(&T) -> bool, @@ -434,7 +692,7 @@ macro_rules! reverse_iter { $( // FIXME(#26925) Remove in favor of `#[derive(Clone)]` - #[$stablility] + #[$stability] impl<'a, T, P> $clone for $rev<'a, T, P> where P: Clone + FnMut(&T) -> bool, @@ -445,7 +703,7 @@ macro_rules! reverse_iter { } )? - #[$stablility] + #[$stability] impl<'a, T, P> Iterator for $rev<'a, T, P> where P: FnMut(&T) -> bool, @@ -463,7 +721,7 @@ macro_rules! reverse_iter { } } - #[$stablility] + #[$stability] impl<'a, T, P> DoubleEndedIterator for $rev<'a, T, P> where P: FnMut(&T) -> bool, @@ -474,10 +732,10 @@ macro_rules! reverse_iter { } } - #[$stablility] + #[$stability] impl FusedIterator for $rev<'_, T, P> where P: FnMut(&T) -> bool {} - #[$stablility] + #[$stability] impl<'a, T, P> SplitIter for $rev<'a, T, P> where P: FnMut(&T) -> bool, @@ -487,19 +745,19 @@ macro_rules! reverse_iter { self.inner.finish() } } - )*}; + }; } #[allow(unused)] macro_rules! iter_n { - ($( - #[$stablility:meta] - #[fused($fused_stablility:meta)] + ( + #[$stability:meta] + #[fused($fused_stability:meta)] $(#[$outer:meta])* $vis:vis struct $iter_n:ident { $str:literal ; $inner:ident } $(: $clone:ident)? - )*) => {$( + ) => { $(#[$outer])* - #[$stablility] + #[$stability] pub struct $iter_n<'a, T: 'a, P> where P: FnMut(&T) -> bool, @@ -515,7 +773,7 @@ macro_rules! iter_n { } $( - #[$stablility] + #[$stability] impl<'a, T: 'a, P> $clone for $iter_n<'a, T, P> where P: FnMut(&T) -> bool, @@ -527,7 +785,7 @@ macro_rules! iter_n { } )? - #[$stablility] + #[$stability] impl fmt::Debug for $iter_n<'_, T, P> where P: Clone + FnMut(&T) -> bool, @@ -537,7 +795,7 @@ macro_rules! iter_n { } } - #[$stablility] + #[$stability] impl<'a, T, P> Iterator for $iter_n<'a, T, P> where P: FnMut(&T) -> bool, @@ -555,7 +813,7 @@ macro_rules! iter_n { } } - #[$fused_stablility] + #[$fused_stability] impl<'a, T, P> FusedIterator for $iter_n<'a, T, P> where P: FnMut(&T) -> bool {} - )*}; + }; } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 101d578bca366..964a33ff9b18b 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -573,7 +573,7 @@ trait SplitIterInternal<'a, P: Pattern<'a>> { where P::Searcher: ReverseSearcher<'a>; - fn get_end(&mut self) -> Option<&'a str>; + fn finish(&mut self) -> Option<&'a str>; fn as_str(&self) -> &'a str; } @@ -711,7 +711,7 @@ macro_rules! split_internal { } #[inline] - fn get_end(&mut self) -> Option<&'a str> { + fn finish(&mut self) -> Option<&'a str> { if self.finished { None } else { @@ -731,7 +731,7 @@ macro_rules! split_internal { #[inline] fn as_str(&self) -> &'a str { - // `Self::get_end` doesn't change `self.start` + // `Self::finish` doesn't change `self.start` if self.finished { "" } else { @@ -823,7 +823,6 @@ split_internal! { } generate_pattern_iterators! { - forward: #[stable(feature = "split_inclusive", since = "1.51.0")] #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] @@ -980,7 +979,7 @@ macro_rules! splitn_internal { 0 => None, 1 => { self.count = 0; - self.iter.get_end() + self.iter.finish() } _ => { self.count -= 1; @@ -1006,7 +1005,7 @@ macro_rules! splitn_internal { 0 => None, 1 => { self.count = 0; - self.iter.get_end() + self.iter.finish() } _ => { self.count -= 1; From 57f4d7a7a2f5ebba32765aea177b7f2472ff7288 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Wed, 22 Dec 2021 23:00:04 -0500 Subject: [PATCH 09/10] Implement `split_initiator`, `split_ends`, and `split_once` variants for string slices --- library/alloc/src/str.rs | 4 +- library/core/src/slice/iter/macros.rs | 5 +- library/core/src/str/iter.rs | 59 +++++ library/core/src/str/mod.rs | 315 +++++++++++++++++++++++++- 4 files changed, 372 insertions(+), 11 deletions(-) diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs index 84fe88a0ce755..b44911e9947ff 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -69,8 +69,8 @@ pub use core::str::{Matches, RMatches}; pub use core::str::{RSplit, Split}; #[unstable(feature = "split_inclusive_variants", issue = "none")] pub use core::str::{ - RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, - SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, + RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, SplitEnds, + SplitInitiator, SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, }; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{RSplitN, SplitN}; diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 2ea91ad9759e2..7517dab0944d2 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -776,8 +776,7 @@ macro_rules! iter_n { #[$stability] impl<'a, T: 'a, P> $clone for $iter_n<'a, T, P> where - P: FnMut(&T) -> bool, - $inner<'a, T, P>: Clone, + P: Clone + FnMut(&T) -> bool, { fn clone(&self) -> Self { Self { inner: self.inner.clone() } @@ -788,7 +787,7 @@ macro_rules! iter_n { #[$stability] impl fmt::Debug for $iter_n<'_, T, P> where - P: Clone + FnMut(&T) -> bool, + P: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct($str).field("inner", &self.inner).finish() diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 964a33ff9b18b..af80309ea4765 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -871,6 +871,35 @@ generate_pattern_iterators! { delegate double ended; } +split_internal! { + SplitInitiatorInternal { + debug: "SplitInitiatorInternal", + skip_leading_empty: skip_leading_empty, + include_leading: false, + include_trailing: false, + } +} + +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_initiator`]. + /// + /// [`split_initiator`]: str::split_initiator + struct SplitInitiator; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_initiator`]. + /// + /// [`rsplit_initiator`]: str::rsplit_initiator + struct RSplitInitiator; + internal: + SplitInitiatorInternal yielding (&'a str); + delegate double ended; +} + split_internal! { SplitTerminatorInternal { debug: "SplitTerminatorInternal", @@ -900,6 +929,36 @@ generate_pattern_iterators! { delegate double ended; } +split_internal! { + SplitEndsInternal { + debug: "SplitEndsInternal", + skip_leading_empty: skip_leading_empty, + skip_trailing_empty: skip_trailing_empty, + include_leading: false, + include_trailing: false, + } +} + +generate_pattern_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`split_ends`]. + /// + /// [`split_ends`]: str::split_ends + struct SplitEnds; + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplit_ends`]. + /// + /// [`rsplit_ends`]: str::rsplit_ends + struct RSplitEnds; + internal: + SplitEndsInternal yielding (&'a str); + delegate double ended; +} + impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { /// Returns remainder of the split string /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index aaa6c5e288b51..0066a62b8e24f 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -14,8 +14,8 @@ mod traits; mod validations; use self::iter::{ - SplitInclusiveInternal, SplitLeftInclusiveInternal, SplitNInclusiveInternal, - SplitNLeftInclusiveInternal, SplitTerminatorInternal, + SplitEndsInternal, SplitInclusiveInternal, SplitInitiatorInternal, SplitLeftInclusiveInternal, + SplitNInclusiveInternal, SplitNLeftInclusiveInternal, SplitTerminatorInternal, }; use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; @@ -74,8 +74,9 @@ pub use iter::SplitInclusive; #[unstable(feature = "split_inclusive_variants", issue = "none")] pub use iter::{ - RSplitInclusive, RSplitLeftInclusive, RSplitNInclusive, RSplitNLeftInclusive, - SplitLeftInclusive, SplitNInclusive, SplitNLeftInclusive, + RSplitEnds, RSplitInclusive, RSplitInitiator, RSplitLeftInclusive, RSplitNInclusive, + RSplitNLeftInclusive, SplitEnds, SplitInitiator, SplitLeftInclusive, SplitNInclusive, + SplitNLeftInclusive, }; #[unstable(feature = "str_internals", issue = "none")] @@ -1443,6 +1444,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." /// .rsplit_inclusive('\n').collect(); /// assert_eq!(v, ["little lamb.", "little lamb\n", "Mary had a little lamb\n"]); @@ -1454,6 +1456,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb.\n" /// .rsplit_inclusive('\n').collect(); /// assert_eq!(v, ["little lamb.\n", "little lamb\n", "Mary had a little lamb\n"]); @@ -1463,6 +1466,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "".rsplit_inclusive('\n').collect(); /// assert_eq!(v.len(), 0); /// ``` @@ -1487,6 +1491,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." /// .split_left_inclusive('\n').collect(); /// assert_eq!(v, ["Mary had a little lamb", "\nlittle lamb", "\nlittle lamb."]); @@ -1498,6 +1503,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" /// .split_left_inclusive('\n').collect(); /// assert_eq!(v, ["\nMary had a little lamb", "\nlittle lamb", "\nlittle lamb.", "\n"]); @@ -1507,6 +1513,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "".split_left_inclusive('\n').collect(); /// assert_eq!(v.len(), 0); /// ``` @@ -1531,6 +1538,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "Mary had a little lamb\nlittle lamb\nlittle lamb." /// .rsplit_left_inclusive('\n').collect(); /// assert_eq!(v, ["\nlittle lamb.", "\nlittle lamb", "Mary had a little lamb"]); @@ -1542,6 +1550,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let v: Vec<&str> = "\nMary had a little lamb\nlittle lamb\nlittle lamb.\n" /// .rsplit_left_inclusive('\n').collect(); /// assert_eq!(v, ["\n", "\nlittle lamb.", "\nlittle lamb", "\nMary had a little lamb"]); @@ -1551,6 +1560,7 @@ impl str { /// /// ``` /// #![feature(split_inclusive_variants)] + /// /// let o = "".rsplit_left_inclusive('\n').next(); /// assert_eq!(o, None); /// ``` @@ -1563,6 +1573,107 @@ impl str { RSplitLeftInclusive(self.split_left_inclusive(pat).0) } + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`split`], except that the leading substring + /// is skipped if empty. + /// + /// [`split`]: str::split + /// + /// This method can be used for string data that is _initiated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, e.g., [`char`], but not for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_initiator`] method can be used. + /// + /// [`rsplit_initiator`]: str::rsplit_initiator + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B".split_initiator('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "..A..B".split_initiator(".").collect(); + /// assert_eq!(v, ["", "A", "", "B"]); + /// + /// let v: Vec<&str> = "A.B:C.D".split_initiator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["A", "B", "C", "D"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_initiator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInitiator<'a, P> { + SplitInitiator(SplitInitiatorInternal::new(self, pat)) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`rsplit`], except that the leading substring is + /// skipped if empty. + /// + /// [`rsplit`]: str::rsplit + /// + /// This method can be used for string data that is _initiated_, + /// rather than _separated_ by a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_initiator`] method can be + /// used. + /// + /// [`split_initiator`]: str::split_initiator + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B".rsplit_initiator('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "..A..B".rsplit_initiator(".").collect(); + /// assert_eq!(v, ["B", "", "A", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".rsplit_initiator(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["D", "C", "B", "A"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_initiator<'a, P>(&'a self, pat: P) -> RSplitInitiator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitInitiator(self.split_initiator(pat).0) + } + /// An iterator over substrings of the given string slice, separated by /// characters matched by a pattern. /// @@ -1620,10 +1731,10 @@ impl str { /// [`char`]: prim@char /// [pattern]: self::pattern /// - /// Equivalent to [`split`], except that the trailing substring is + /// Equivalent to [`rsplit`], except that the trailing substring is /// skipped if empty. /// - /// [`split`]: str::split + /// [`rsplit`]: str::rsplit /// /// This method can be used for string data that is _terminated_, /// rather than _separated_ by a pattern. @@ -1660,6 +1771,107 @@ impl str { RSplitTerminator(self.split_terminator(pat).0) } + /// An iterator over substrings of the given string slice, separated by + /// characters matched by a pattern. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`split`], except that the leading and trailing + /// substrings are skipped if empty. + /// + /// [`split`]: str::split + /// + /// This method can be used for string data that _separates_, + /// rather than _is separated by_, a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator will be a [`DoubleEndedIterator`] if the pattern + /// allows a reverse search and forward/reverse search yields the same + /// elements. This is true for, e.g., [`char`], but not for `&str`. + /// + /// If the pattern allows a reverse search but its results might differ + /// from a forward search, the [`rsplit_ends`] method can be used. + /// + /// [`rsplit_ends`]: str::rsplit_ends + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B.".split_ends('.').collect(); + /// assert_eq!(v, ["A", "B"]); + /// + /// let v: Vec<&str> = "..A..B..".split_ends(".").collect(); + /// assert_eq!(v, ["", "A", "", "B", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".split_ends(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["A", "B", "C", "D"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_ends<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitEnds<'a, P> { + SplitEnds(SplitEndsInternal::new(self, pat)) + } + + /// An iterator over substrings of `self`, separated by characters + /// matched by a pattern and yielded in reverse order. + /// + /// The [pattern] can be a `&str`, [`char`], a slice of [`char`]s, or a + /// function or closure that determines if a character matches. + /// + /// [`char`]: prim@char + /// [pattern]: self::pattern + /// + /// Equivalent to [`rsplit`], except that the leading and trailing + /// substring are skipped if empty. + /// + /// [`rsplit`]: str::rsplit + /// + /// This method can be used for string data that _separates_, + /// rather than _is separated by_, a pattern. + /// + /// # Iterator behavior + /// + /// The returned iterator requires that the pattern supports a + /// reverse search, and it will be double ended if a forward/reverse + /// search yields the same elements. + /// + /// For iterating from the front, the [`split_ends`] method can be + /// used. + /// + /// [`split_ends`]: str::split_ends + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// let v: Vec<&str> = ".A.B.".rsplit_ends('.').collect(); + /// assert_eq!(v, ["B", "A"]); + /// + /// let v: Vec<&str> = "..A..B..".rsplit_ends(".").collect(); + /// assert_eq!(v, ["", "B", "", "A", ""]); + /// + /// let v: Vec<&str> = "A.B:C.D".rsplit_ends(&['.', ':'][..]).collect(); + /// assert_eq!(v, ["D", "C", "B", "A"]); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_ends<'a, P>(&'a self, pat: P) -> RSplitEnds<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + RSplitEnds(self.split_ends(pat).0) + } + /// An iterator over substrings of the given string slice, separated by a /// pattern, restricted to returning at most `n` items. /// @@ -2048,6 +2260,97 @@ impl str { // SAFETY: `Searcher` is known to return valid indices. unsafe { Some((self.get_unchecked(..start), self.get_unchecked(end..))) } } + /// Splits the string on the first occurrence of the specified delimiter and + /// returns prefix including delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".split_once_inclusive('='), None); + /// assert_eq!("cfg=foo".split_once_inclusive('='), Some(("cfg=", "foo"))); + /// assert_eq!("cfg=foo=bar".split_once_inclusive('='), Some(("cfg=", "foo=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_once_inclusive<'a, P: Pattern<'a>>( + &'a self, + delimiter: P, + ) -> Option<(&'a str, &'a str)> { + let (_, end) = delimiter.into_searcher(self).next_match()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..end), self.get_unchecked(end..))) } + } + + /// Splits the string on the last occurrence of the specified delimiter and + /// returns prefix including delimiter and suffix after delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".rsplit_once_inclusive('='), None); + /// assert_eq!("cfg=foo".rsplit_once_inclusive('='), Some(("cfg=", "foo"))); + /// assert_eq!("cfg=foo=bar".rsplit_once_inclusive('='), Some(("cfg=foo=", "bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_once_inclusive<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + let (_, end) = delimiter.into_searcher(self).next_match_back()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..end), self.get_unchecked(end..))) } + } + + /// Splits the string on the first occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix including delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".split_once_left_inclusive('='), None); + /// assert_eq!("cfg=foo".split_once_left_inclusive('='), Some(("cfg", "=foo"))); + /// assert_eq!("cfg=foo=bar".split_once_left_inclusive('='), Some(("cfg", "=foo=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn split_once_left_inclusive<'a, P: Pattern<'a>>( + &'a self, + delimiter: P, + ) -> Option<(&'a str, &'a str)> { + let (start, _) = delimiter.into_searcher(self).next_match()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(start..))) } + } + + /// Splits the string on the last occurrence of the specified delimiter and + /// returns prefix before delimiter and suffix including delimiter. + /// + /// # Examples + /// + /// ``` + /// #![feature(split_inclusive_variants)] + /// + /// assert_eq!("cfg".rsplit_once_left_inclusive('='), None); + /// assert_eq!("cfg=foo".rsplit_once_left_inclusive('='), Some(("cfg", "=foo"))); + /// assert_eq!("cfg=foo=bar".rsplit_once_left_inclusive('='), Some(("cfg=foo", "=bar"))); + /// ``` + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[inline] + pub fn rsplit_once_left_inclusive<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + let (start, _) = delimiter.into_searcher(self).next_match_back()?; + // SAFETY: `Searcher` is known to return valid indices. + unsafe { Some((self.get_unchecked(..start), self.get_unchecked(start..))) } + } /// An iterator over the disjoint matches of a pattern within the given string /// slice. From bfc9df07170d109afb05e02f1fada7c505974a54 Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Thu, 24 Mar 2022 21:55:05 -0400 Subject: [PATCH 10/10] WIP --- library/core/src/slice/iter.rs | 96 ++- library/core/src/slice/iter/macros.rs | 24 +- library/core/src/slice/mod.rs | 16 +- library/core/src/str/iter.rs | 856 +++++++++++++++----------- library/core/src/str/mod.rs | 32 +- 5 files changed, 617 insertions(+), 407 deletions(-) diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 216e465637b2d..e6257711643ac 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -376,6 +376,7 @@ pub(super) trait SplitIter: DoubleEndedIterator { split_iter! { #[stable(feature = "rust1", since = "1.0.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] #[fused(stable(feature = "fused", since = "1.26.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over subslices separated by elements that match a predicate @@ -393,12 +394,16 @@ split_iter! { /// [`split`]: slice::split /// [slices]: slice struct Split { - #[stable(feature = "core_impl_debug", since = "1.9.0")] - debug: "Split", include_leading: false, include_trailing: false, } +} +impl<'a, T, P> Split<'a, T, P> +where + T: 'a, + P: FnMut(&T) -> bool, +{ /// Returns a slice which contains items not yet handled by split. /// # Example /// @@ -417,6 +422,7 @@ split_iter! { split_iter! { #[stable(feature = "rust1", since = "1.0.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] #[fused(stable(feature = "fused", since = "1.26.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the mutable subslices of the vector which are separated @@ -434,8 +440,6 @@ split_iter! { /// [`split_mut`]: slice::split_mut /// [slices]: slice struct SplitMut { - #[stable(feature = "core_impl_debug", since = "1.9.0")] - debug: "SplitMut", include_leading: false, include_trailing: false, } @@ -443,6 +447,7 @@ split_iter! { split_iter! { #[stable(feature = "split_inclusive", since = "1.51.0")] + #[debug(stable(feature = "core_impl_debug", since = "1.9.0"))] #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over subslices separated by elements that match a predicate @@ -461,8 +466,6 @@ split_iter! { /// [`split_inclusive`]: slice::split_inclusive /// [slices]: slice struct SplitInclusive { - #[stable(feature = "split_inclusive", since = "1.51.0")] - debug: "SplitInclusive", include_leading: false, include_trailing: true, } @@ -470,6 +473,7 @@ split_iter! { split_iter! { #[stable(feature = "split_inclusive", since = "1.51.0")] + #[debug(stable(feature = "split_inclusive", since = "1.51.0"))] #[fused(stable(feature = "split_inclusive", since = "1.51.0"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the mutable subslices of the vector which are separated @@ -488,8 +492,6 @@ split_iter! { /// [`split_inclusive_mut`]: slice::split_inclusive_mut /// [slices]: slice struct SplitInclusiveMut { - #[stable(feature = "split_inclusive", since = "1.51.0")] - debug: "SplitInclusiveMut", include_leading: false, include_trailing: true, } @@ -497,6 +499,7 @@ split_iter! { split_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[debug(stable(feature = "split_inclusive", since = "1.51.0"))] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over subslices separated by elements that match a predicate @@ -517,8 +520,6 @@ split_iter! { /// [`split_left_inclusive`]: slice::split_left_inclusive /// [slices]: slice struct SplitLeftInclusive { - #[unstable(feature = "split_inclusive_variants", issue = "none")] - debug: "SplitLeftInclusive", include_leading: true, include_trailing: false, } @@ -526,6 +527,7 @@ split_iter! { split_iter! { #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[debug(unstable(feature = "split_inclusive_variants", issue = "none"))] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] #[must_use = "iterators are lazy and do nothing unless consumed"] /// An iterator over the mutable subslices of the vector which are separated @@ -547,8 +549,6 @@ split_iter! { /// [`split_left_inclusive_mut`]: slice::split_left_inclusive_mut /// [slices]: slice struct SplitLeftInclusiveMut { - #[unstable(feature = "split_inclusive_variants", issue = "none")] - debug: "SplitLeftInclusiveMut", include_leading: true, include_trailing: false, } @@ -571,7 +571,7 @@ reverse_iter! { /// /// [`rsplit`]: slice::rsplit /// [slices]: slice - pub struct RSplit { "RSplit"; Split }: Clone + pub struct RSplit { inner: Split }: Clone } reverse_iter! { @@ -594,7 +594,7 @@ reverse_iter! { /// /// [`rsplit_left_inclusive`]: slice::rsplit_inclusive /// [slices]: slice - pub struct RSplitInclusive { "RSplitInclusive"; SplitInclusive }: Clone + pub struct RSplitInclusive { inner: SplitInclusive }: Clone } reverse_iter! { @@ -617,7 +617,7 @@ reverse_iter! { /// /// [`rsplit_left_inclusive`]: slice::rsplit_left_inclusive /// [slices]: slice - pub struct RSplitLeftInclusive { "RSplitLeftInclusive"; SplitLeftInclusive }: Clone + pub struct RSplitLeftInclusive { inner: SplitLeftInclusive }: Clone } reverse_iter! { @@ -637,7 +637,7 @@ reverse_iter! { /// /// [`rsplit_mut`]: slice::rsplit_mut /// [slices]: slice - pub struct RSplitMut { "RSplitMut"; SplitMut } + pub struct RSplitMut { inner: SplitMut } } reverse_iter! { @@ -660,7 +660,7 @@ reverse_iter! { /// /// [`rsplit_inclusive_mut`]: slice::rsplit_inclusive_mut /// [slices]: slice - pub struct RSplitInclusiveMut { "RSplitInclusiveMut" ; SplitInclusiveMut } + pub struct RSplitInclusiveMut { inner: SplitInclusiveMut } } reverse_iter! { @@ -683,7 +683,7 @@ reverse_iter! { /// /// [`rsplit_left_inclusive_mut`]: slice::rsplit_left_inclusive_mut /// [slices]: slice - pub struct RSplitLeftInclusiveMut { "RSplitLeftInclusiveMut" ; SplitLeftInclusiveMut } + pub struct RSplitLeftInclusiveMut { inner: SplitLeftInclusiveMut } } /// An private iterator over subslices separated by elements that @@ -741,7 +741,10 @@ iter_n! { /// /// [`splitn`]: slice::splitn /// [slices]: slice - pub struct SplitN {"SplitN"; Split }: Clone + pub struct SplitN { inner: Split }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -763,7 +766,10 @@ iter_n! { /// /// [`rsplitn`]: slice::rsplitn /// [slices]: slice - pub struct RSplitN {"RSplitN"; RSplit }: Clone + pub struct RSplitN { inner: RSplit }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -784,7 +790,10 @@ iter_n! { /// /// [`splitn_mut`]: slice::splitn_mut /// [slices]: slice - pub struct SplitNMut {"SplitNMut"; SplitMut } + pub struct SplitNMut { inner: SplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -806,7 +815,10 @@ iter_n! { /// /// [`rsplitn_mut`]: slice::rsplitn_mut /// [slices]: slice - pub struct RSplitNMut {"RSplitNMut"; RSplitMut } + pub struct RSplitNMut { inner: RSplitMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -830,7 +842,10 @@ iter_n! { /// /// [`splitn_inclusive`]: slice::splitn_inclusive /// [slices]: slice - pub struct SplitNInclusive {"SplitNInclusive"; SplitInclusive}: Clone + pub struct SplitNInclusive { inner: SplitInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -854,7 +869,10 @@ iter_n! { /// /// [`splitn_left_inclusive`]: slice::splitn_left_inclusive /// [slices]: slice - pub struct SplitNLeftInclusive {"SplitNLeftInclusive"; SplitLeftInclusive}: Clone + pub struct SplitNLeftInclusive { inner: SplitLeftInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -878,7 +896,10 @@ iter_n! { /// /// [`rsplitn_inclusive`]: slice::rsplitn_inclusive /// [slices]: slice - pub struct RSplitNInclusive {"RSplitNInclusive"; RSplitInclusive}: Clone + pub struct RSplitNInclusive { inner: RSplitInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -902,7 +923,10 @@ iter_n! { /// /// [`rsplitn_left_inclusive`]: slice::rsplitn_left_inclusive /// [slices]: slice - pub struct RSplitNLeftInclusive {"RSplitNLeftInclusive"; RSplitLeftInclusive}: Clone + pub struct RSplitNLeftInclusive { inner: RSplitLeftInclusive }: Clone + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -926,7 +950,10 @@ iter_n! { /// /// [`splitn_inclusive_mut`]: slice::splitn_inclusive_mut /// [slices]: slice - pub struct SplitNInclusiveMut {"SplitNInclusiveMut"; SplitInclusiveMut} + pub struct SplitNInclusiveMut { inner: SplitInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -950,7 +977,10 @@ iter_n! { /// /// [`splitn_left_inclusive_mut`]: slice::splitn_left_inclusive_mut /// [slices]: slice - pub struct SplitNLeftInclusiveMut {"SplitNLeftInclusiveMut"; SplitLeftInclusiveMut} + pub struct SplitNLeftInclusiveMut { inner: SplitLeftInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -974,7 +1004,10 @@ iter_n! { /// /// [`rsplitn_inclusive_mut`]: slice::rsplitn_inclusive_mut /// [slices]: slice - pub struct RSplitNInclusiveMut {"RSplitNInclusiveMut"; RSplitInclusiveMut} + pub struct RSplitNInclusiveMut { inner: RSplitInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } iter_n! { @@ -998,7 +1031,10 @@ iter_n! { /// /// [`rsplitn_left_inclusive_mut`]: slice::rsplitn_left_inclusive_mut /// [slices]: slice - pub struct RSplitNLeftInclusiveMut {"RSplitNLeftInclusiveMut"; RSplitLeftInclusiveMut} + pub struct RSplitNLeftInclusiveMut { inner: RSplitLeftInclusiveMut } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; } /// An iterator over overlapping subslices of length `size`. diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs index 7517dab0944d2..517a987198683 100644 --- a/library/core/src/slice/iter/macros.rs +++ b/library/core/src/slice/iter/macros.rs @@ -400,14 +400,13 @@ macro_rules! iterator { macro_rules! split_iter { ( #[$stability:meta] + #[debug($debug_stability:meta)] #[fused($fused_stability:meta)] $(#[$outer:meta])* struct $split_iter:ident< $(shared_ref: & $lt:lifetime)? $(mut_ref: & $m_lt:lifetime)? > { - #[$debug_stability:meta] - debug: $debug_name:literal, include_leading: $include_leading:literal, include_trailing: $include_trailing:literal, } @@ -442,7 +441,7 @@ macro_rules! split_iter { P: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct($debug_name) + f.debug_struct(stringify!(split_iter)) .field("v", &self.v) .field("finished", &self.finished) .finish() @@ -659,7 +658,7 @@ macro_rules! reverse_iter { ( #[$stability:meta] $(#[$outer:meta])* - $vis:vis struct $rev:ident { $str:literal ; $inner:ident } $(: $clone:ident)? + $vis:vis struct $rev:ident { inner: $inner:ident } $(: $clone:ident)? ) => { $(#[$outer])* #[$stability] @@ -683,7 +682,7 @@ macro_rules! reverse_iter { P: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct($str) + f.debug_struct(stringify!($rev)) .field("v", &self.inner.v) .field("finished", &self.inner.finished) .finish() @@ -754,7 +753,10 @@ macro_rules! iter_n { #[$stability:meta] #[fused($fused_stability:meta)] $(#[$outer:meta])* - $vis:vis struct $iter_n:ident { $str:literal ; $inner:ident } $(: $clone:ident)? + $vis:vis struct $iter_n:ident { inner: $inner:ident } $(: $clone:ident)? + + $(#[$max_items_attrs:meta])* + fn max_items; ) => { $(#[$outer])* #[$stability] @@ -790,7 +792,7 @@ macro_rules! iter_n { P: FnMut(&T) -> bool, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct($str).field("inner", &self.inner).finish() + f.debug_struct(stringify!($iter_n)).field("inner", &self.inner).finish() } } @@ -814,5 +816,13 @@ macro_rules! iter_n { #[$fused_stability] impl<'a, T, P> FusedIterator for $iter_n<'a, T, P> where P: FnMut(&T) -> bool {} + + impl<'a, T, P> $inner<'a, T, P> where P: FnMut(&T) -> bool { + $(#[$max_items_attrs])* + #[inline] + pub fn max_items(self, n: usize) -> $iter_n<'a, T, P> { + $iter_n::new(self, n) + } + } }; } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 1c5e5617f7ba2..5c65f4c71bd27 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -2262,7 +2262,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitN::new(self.split(pred), n) + self.split(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2288,7 +2288,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNMut::new(self.split_mut(pred), n) + self.split_mut(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2317,7 +2317,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitN::new(self.rsplit(pred), n) + self.rsplit(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2344,7 +2344,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNMut::new(self.rsplit_mut(pred), n) + self.rsplit_mut(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2369,7 +2369,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNInclusive::new(self.split_inclusive(pred), n) + self.split_inclusive(pred).max_items(n) } /// Returns an iterator over mutable subslices separated by elements that @@ -2395,7 +2395,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNInclusiveMut::new(self.split_inclusive_mut(pred), n) + self.split_inclusive_mut(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match @@ -2424,7 +2424,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNInclusive::new(self.rsplit_inclusive(pred), n) + self.rsplit_inclusive(pred).max_items(n) } /// Returns an iterator over mutable subslices separated by elements that @@ -2450,7 +2450,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNInclusiveMut::new(self.rsplit_inclusive_mut(pred), n) + self.rsplit_inclusive_mut(pred).max_items(n) } /// Returns an iterator over subslices separated by elements that match diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index af80309ea4765..a40e990b39fc4 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -358,11 +358,19 @@ unsafe impl TrustedRandomAccessNoCoerce for Bytes<'_> { /// This macro generates a Clone impl for string pattern API /// wrapper types of the form X<'a, P> macro_rules! derive_pattern_clone { - (clone $t:ident with |$s:ident| $e:expr) => { + ( + $(#[$impl_attr:meta])* + clone $t:ident + $(where Searcher: ($where_clause:path))? + with $(#[$fn_attr:meta])* |$s:ident| $e:expr + ) => { + $(#[$impl_attr])* impl<'a, P> Clone for $t<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern<'a, Searcher: $($where_clause +)? Clone>, { + $(#[$fn_attr])* + #[inline] fn clone(&self) -> Self { let $s = self; $e @@ -409,21 +417,27 @@ macro_rules! derive_pattern_clone { /// so the two wrapper structs implement `Iterator` /// and `DoubleEndedIterator` depending on the concrete pattern type, leading /// to the complex impls seen above. +/// +/// In addition, when requested, as_str methods are are also generated for all iterators. macro_rules! generate_pattern_iterators { { // Forward iterator forward: #[$forward_stability_attribute:meta] - #[fused($fused_forward_stability_attribute:meta)] + #[fused($forward_fused_stability_attribute:meta)] $(#[$forward_iterator_attribute:meta])* struct $forward_iterator:ident; + $($(#[$forward_as_str_attribute:meta])* + fn as_str;)? // Reverse iterator reverse: #[$reverse_stability_attribute:meta] - #[fused($fused_reverse_stability_attribute:meta)] + #[fused($reverse_fused_stability_attribute:meta)] $(#[$reverse_iterator_attribute:meta])* struct $reverse_iterator:ident; + $($(#[$reverse_as_str_attribute:meta])* + fn as_str;)? // Internal almost-iterator that is being delegated to internal: @@ -434,8 +448,14 @@ macro_rules! generate_pattern_iterators { } => { $(#[$forward_iterator_attribute])* #[$forward_stability_attribute] + #[repr(transparent)] pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + derive_pattern_clone! { + #[$forward_stability_attribute] + clone $forward_iterator with |s| Self(s.0.clone()) + } + #[$forward_stability_attribute] impl<'a, P> fmt::Debug for $forward_iterator<'a, P> where @@ -458,25 +478,31 @@ macro_rules! generate_pattern_iterators { } } - // FIXME(#26925) Remove in favor of `#[derive(Clone)]` - #[$forward_stability_attribute] - impl<'a, P> Clone for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $forward_iterator(self.0.clone()) + $(impl<'a, P: Pattern<'a>> $forward_iterator<'a, P> { + $(#[$forward_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.0.as_str() } - } + })? + + #[$forward_fused_stability_attribute] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} $(#[$reverse_iterator_attribute])* #[$reverse_stability_attribute] - pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + #[repr(transparent)] + pub struct $reverse_iterator<'a, P>(pub(super) $internal_iterator<'a, P>) where P: Pattern<'a, Searcher: ReverseSearcher<'a>>; + + derive_pattern_clone! { + #[$reverse_stability_attribute] + clone $reverse_iterator where Searcher: (ReverseSearcher<'a>) with |s| Self(s.0.clone()) + } #[$reverse_stability_attribute] impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: fmt::Debug>, + P: Pattern<'a, Searcher: ReverseSearcher<'a> + fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple(stringify!($reverse_iterator)) @@ -498,20 +524,18 @@ macro_rules! generate_pattern_iterators { } } - #[$reverse_stability_attribute] - impl<'a, P> Clone for $reverse_iterator<'a, P> + $(impl<'a, P> $reverse_iterator<'a, P> where - P: Pattern<'a, Searcher: Clone>, + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - fn clone(&self) -> Self { - $reverse_iterator(self.0.clone()) + $(#[$reverse_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.0.as_str() } - } - - #[$fused_forward_stability_attribute] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + })? - #[$fused_reverse_stability_attribute] + #[$reverse_fused_stability_attribute] impl<'a, P> FusedIterator for $reverse_iterator<'a, P> where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, @@ -565,13 +589,13 @@ macro_rules! generate_pattern_iterators { } => {} } -// Making this a trait suppresses some `unused` lints -trait SplitIterInternal<'a, P: Pattern<'a>> { +trait SplitIterInternal<'a>: Sized { + type Pat: Pattern<'a>; fn next(&mut self) -> Option<&'a str>; fn next_back(&mut self) -> Option<&'a str> where - P::Searcher: ReverseSearcher<'a>; + <>::Pat as Pattern<'a>>::Searcher: ReverseSearcher<'a>; fn finish(&mut self) -> Option<&'a str>; @@ -581,7 +605,6 @@ trait SplitIterInternal<'a, P: Pattern<'a>> { macro_rules! split_internal { ( $split_struct:ident { - debug: $name_str:literal, $(skip_leading_empty: $skip_leading_empty:ident,)? $(skip_trailing_empty: $skip_trailing_empty:ident,)? include_leading: $include_leading:literal, @@ -607,7 +630,7 @@ macro_rules! split_internal { P: Pattern<'a, Searcher: fmt::Debug>, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct($name_str) + f.debug_struct(stringify!(split_struct)) .field("start", &self.start) .field("end", &self.end) .field("matcher", &self.matcher) @@ -632,7 +655,9 @@ macro_rules! split_internal { } } - impl<'a, P: Pattern<'a>> SplitIterInternal<'a, P> for $split_struct<'a, P> { + impl<'a, P: Pattern<'a>> SplitIterInternal<'a> for $split_struct<'a, P> { + type Pat = P; + #[inline] fn next(&mut self) -> Option<&'a str> { if self.finished { @@ -743,9 +768,189 @@ macro_rules! split_internal { } } +macro_rules! generate_n_iterators { + ( + forward: + #[$forward_stability_attribute:meta] + #[fused($forward_fused_stability_attribute:meta)] + $(#[$forward_iterator_attribute:meta])* + struct $forward_n_iterator:ident { inner: $forward_inner_iterator:ident } + + $(#[$forward_max_items_attribute:meta])* + fn max_items; + + $($(#[$forward_as_str_attribute:meta])* + fn as_str;)? + reverse: + #[$reverse_stability_attribute:meta] + #[fused($reverse_fused_stability_attribute:meta)] + $(#[$reverse_iterator_attribute:meta])* + struct $reverse_n_iterator:ident { inner: $reverse_inner_iterator:ident } + + $(#[$reverse_max_items_attribute:meta])* + fn max_items; + + $($(#[$reverse_as_str_attribute:meta])* + fn as_str;)? + ) => { + #[$forward_stability_attribute] + $(#[$forward_iterator_attribute])* + pub struct $forward_n_iterator<'a, P: Pattern<'a>> { + iter: $forward_inner_iterator<'a, P>, + count: usize + } + + derive_pattern_clone! { + #[$forward_stability_attribute] + clone $forward_n_iterator with |s| Self { iter: s.iter.clone(), count: s.count } + } + + #[$forward_stability_attribute] + impl<'a, P> fmt::Debug for $forward_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($forward_n_iterator)) + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } + } + + #[$forward_stability_attribute] + impl<'a, P: Pattern<'a>> Iterator for $forward_n_iterator<'a, P> { + type Item = <$forward_inner_iterator<'a, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.0.finish() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.count)) + } + } + + $(impl<'a, P: Pattern<'a>> $forward_n_iterator<'a, P> { + $(#[$forward_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } + })? + + impl<'a, P: Pattern<'a>> $forward_inner_iterator<'a, P> { + $(#[$forward_max_items_attribute])* + #[inline] + pub fn max_items(self, n: usize) -> $forward_n_iterator<'a, P> { + $forward_n_iterator { iter: self, count: n } + } + } + + #[$forward_fused_stability_attribute] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_n_iterator<'a, P> {} + + #[$reverse_stability_attribute] + $(#[$reverse_iterator_attribute])* + pub struct $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + iter: $reverse_inner_iterator<'a, P>, + count: usize + } + + derive_pattern_clone! { + #[$reverse_stability_attribute] + clone $reverse_n_iterator where Searcher: (ReverseSearcher<'a>) with |s| Self { iter: s.iter.clone(), count: s.count } + } + + #[$reverse_stability_attribute] + impl<'a, P> fmt::Debug for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a> + fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct(stringify!($reverse_n_iterator)) + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } + } + + #[$reverse_stability_attribute] + impl<'a, P> Iterator for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + type Item = <$reverse_inner_iterator<'a, P> as Iterator>::Item; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.0.finish() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, Some(self.count)) + } + } + + $(impl<'a, P> $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + $(#[$reverse_as_str_attribute])* + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } + })? + + + impl<'a, P> $reverse_inner_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + $(#[$reverse_max_items_attribute])* + #[inline] + pub fn max_items(self, n: usize) -> $reverse_n_iterator<'a, P> { + $reverse_n_iterator { iter: self, count: n } + } + } + + #[$reverse_fused_stability_attribute] + impl<'a, P> FusedIterator for $reverse_n_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + {} + } +} + split_internal! { SplitInternal { - debug: "SplitInternal", include_leading: false, include_trailing: false, } @@ -759,6 +964,23 @@ generate_pattern_iterators! { /// /// [`split`]: str::split struct Split; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".split(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + reverse: #[stable(feature = "rust1", since = "1.0.0")] #[fused(stable(feature = "fused", since = "1.26.0"))] @@ -766,56 +988,60 @@ generate_pattern_iterators! { /// /// [`rsplit`]: str::rsplit struct RSplit; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplit(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + internal: SplitInternal yielding (&'a str); delegate double ended; } -impl<'a, P: Pattern<'a>> Split<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".split(' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "had a little lamb"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} +generate_n_iterators! { + forward: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`splitn`]. + /// + /// [`splitn`]: str::splitn + struct SplitN { inner: Split } -impl<'a, P: Pattern<'a>> RSplit<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".rsplit(' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "Mary had a little"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + + reverse: + #[stable(feature = "rust1", since = "1.0.0")] + #[fused(stable(feature = "fused", since = "1.26.0"))] + /// Created with the method [`rsplitn`]. + /// + /// [`rsplitn`]: str::rsplitn + struct RSplitN { inner: RSplit } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; } split_internal! { SplitInclusiveInternal { - debug: "SplitInclusiveInternal", skip_trailing_empty: skip_trailing_empty, include_leading: false, include_trailing: true, @@ -830,6 +1056,23 @@ generate_pattern_iterators! { /// /// [`split_inclusive`]: str::split_inclusive struct SplitInclusive; + + /// Returns remainder of the split string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// let mut split = "Mary had a little lamb".split_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + reverse: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] @@ -837,14 +1080,47 @@ generate_pattern_iterators! { /// /// [`rsplit_inclusive`]: str::rsplit_inclusive struct RSplitInclusive; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + internal: SplitInclusiveInternal yielding (&'a str); delegate double ended; } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_inclusive`]. + /// + /// [`splitn_inclusive`]: str::splitn_inclusive + struct SplitNInclusive { inner: SplitInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_inclusive`]. + /// + /// [`rsplitn_inclusive`]: str::rsplitn_inclusive + struct RSplitNInclusive { inner: RSplitInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + split_internal! { SplitLeftInclusiveInternal { - debug: "SplitLeftInclusiveInternal", skip_leading_empty: skip_leading_empty, include_leading: true, include_trailing: false, @@ -859,6 +1135,24 @@ generate_pattern_iterators! { /// /// [`split_left_inclusive`]: str::split_left_inclusive struct SplitLeftInclusive; + + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_inclusive_variants)] + /// let mut split = "Mary had a little lamb".split_left_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), " had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + reverse: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] @@ -866,14 +1160,47 @@ generate_pattern_iterators! { /// /// [`rsplit_left_inclusive`]: str::rsplit_left_inclusive struct RSplitLeftInclusive; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + internal: SplitLeftInclusiveInternal yielding (&'a str); delegate double ended; } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`splitn_left_inclusive`]. + /// + /// [`splitn_left_inclusive`]: str::splitn_left_inclusive + struct SplitNLeftInclusive { inner: SplitLeftInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + /// Created with the method [`rsplitn_left_inclusive`]. + /// + /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive + struct RSplitNLeftInclusive { inner: RSplitLeftInclusive } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + split_internal! { SplitInitiatorInternal { - debug: "SplitInitiatorInternal", skip_leading_empty: skip_leading_empty, include_leading: false, include_trailing: false, @@ -888,6 +1215,10 @@ generate_pattern_iterators! { /// /// [`split_initiator`]: str::split_initiator struct SplitInitiator; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + reverse: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] @@ -895,14 +1226,41 @@ generate_pattern_iterators! { /// /// [`rsplit_initiator`]: str::rsplit_initiator struct RSplitInitiator; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + internal: SplitInitiatorInternal yielding (&'a str); delegate double ended; } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct SplitNInitiator { inner: SplitInitiator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct RSplitNInitiator { inner: RSplitInitiator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + split_internal! { SplitTerminatorInternal { - debug: "SplitTerminatorInternal", skip_trailing_empty: skip_trailing_empty, include_leading: false, include_trailing: false, @@ -917,6 +1275,23 @@ generate_pattern_iterators! { /// /// [`split_terminator`]: str::split_terminator struct SplitTerminator; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".split_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), ".B.."); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + reverse: #[stable(feature = "rust1", since = "1.0.0")] #[fused(stable(feature = "fused", since = "1.26.0"))] @@ -924,14 +1299,54 @@ generate_pattern_iterators! { /// /// [`rsplit_terminator`]: str::rsplit_terminator struct RSplitTerminator; + + /// Returns remainder of the split string. + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".rsplit_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), "A..B"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + internal: SplitTerminatorInternal yielding (&'a str); delegate double ended; } +generate_n_iterators! { + forward: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct SplitNTerminator { inner: SplitTerminator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; + + reverse: + #[unstable(feature = "split_inclusive_variants", issue = "none")] + #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] + struct RSplitNTerminator { inner: RSplitTerminator } + + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; + + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; +} + split_internal! { SplitEndsInternal { - debug: "SplitEndsInternal", skip_leading_empty: skip_leading_empty, skip_trailing_empty: skip_trailing_empty, include_leading: false, @@ -947,6 +1362,10 @@ generate_pattern_iterators! { /// /// [`split_ends`]: str::split_ends struct SplitEnds; + + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; + reverse: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] @@ -954,249 +1373,37 @@ generate_pattern_iterators! { /// /// [`rsplit_ends`]: str::rsplit_ends struct RSplitEnds; - internal: - SplitEndsInternal yielding (&'a str); - delegate double ended; -} - -impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "A..B..".split_terminator('.'); - /// assert_eq!(split.as_str(), "A..B.."); - /// split.next(); - /// assert_eq!(split.as_str(), ".B.."); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} - -impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "A..B..".rsplit_terminator('.'); - /// assert_eq!(split.as_str(), "A..B.."); - /// split.next(); - /// assert_eq!(split.as_str(), "A..B"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} - -macro_rules! splitn_internal { - ( - struct $splitn_struct:ident { - debug: $debug_str:literal, - iter: $inner_iter:ident, - } - ) => { - derive_pattern_clone! { - clone $splitn_struct - with |s| $splitn_struct { iter: s.iter.clone(), ..*s } - } - - pub(super) struct $splitn_struct<'a, P: Pattern<'a>> { - pub(super) iter: $inner_iter<'a, P>, - /// The number of splits remaining - pub(super) count: usize, - } - - impl<'a, P> fmt::Debug for $splitn_struct<'a, P> - where - P: Pattern<'a, Searcher: fmt::Debug>, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct($debug_str) - .field("iter", &self.iter) - .field("count", &self.count) - .finish() - } - } - - impl<'a, P: Pattern<'a>> $splitn_struct<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.finish() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[unstable(feature = "str_split_as_str", issue = "77998")] - #[allow(unused)] // FIXME complete this feature? - fn as_str(&self) -> &'a str { - self.iter.as_str() - } - } - impl<'a, P: Pattern<'a>> $splitn_struct<'a, P> - where - P::Searcher: ReverseSearcher<'a>, - { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.finish() - } - _ => { - self.count -= 1; - self.iter.next_back() - } - } - } - } - }; -} - -splitn_internal! { - struct SplitNInternal { - debug: "SplitNInternal", - iter: SplitInternal, - } -} + #[unstable(feature = "str_split_as_str", issue = "77998")] + fn as_str; -generate_pattern_iterators! { - forward: - #[stable(feature = "rust1", since = "1.0.0")] - #[fused(stable(feature = "fused", since = "1.26.0"))] - /// Created with the method [`splitn`]. - /// - /// [`splitn`]: str::splitn - struct SplitN; - reverse: - #[stable(feature = "rust1", since = "1.0.0")] - #[fused(stable(feature = "fused", since = "1.26.0"))] - /// Created with the method [`rsplitn`]. - /// - /// [`rsplitn`]: str::rsplitn - struct RSplitN; internal: - SplitNInternal yielding (&'a str); - delegate single ended; -} - -splitn_internal! { - struct SplitNInclusiveInternal { - debug: "SplitNInclusiveInternal", - iter: SplitInclusiveInternal, - } + SplitEndsInternal yielding (&'a str); + delegate double ended; } -generate_pattern_iterators! { +generate_n_iterators! { forward: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] - /// Created with the method [`splitn_inclusive`]. - /// - /// [`splitn_inclusive`]: str::splitn_inclusive - struct SplitNInclusive; - reverse: + struct SplitNEnds { inner: SplitEnds } + #[unstable(feature = "split_inclusive_variants", issue = "none")] - #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] - /// Created with the method [`rsplitn_inclusive`]. - /// - /// [`rsplitn_inclusive`]: str::rsplitn_inclusive - struct RSplitNInclusive; - internal: - SplitNInclusiveInternal yielding (&'a str); - delegate single ended; -} + fn max_items; -splitn_internal! { - struct SplitNLeftInclusiveInternal { - debug: "SplitNLeftInclusiveInternal", - iter: SplitLeftInclusiveInternal, - } -} + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; -generate_pattern_iterators! { - forward: - #[unstable(feature = "split_inclusive_variants", issue = "none")] - #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] - /// Created with the method [`splitn_left_inclusive`]. - /// - /// [`splitn_left_inclusive`]: str::splitn_left_inclusive - struct SplitNLeftInclusive; reverse: #[unstable(feature = "split_inclusive_variants", issue = "none")] #[fused(unstable(feature = "split_inclusive_variants", issue = "none"))] - /// Created with the method [`rsplitn_left_inclusive`]. - /// - /// [`rsplitn_left_inclusive`]: str::rsplitn_left_inclusive - struct RSplitNLeftInclusive; - internal: - SplitNLeftInclusiveInternal yielding (&'a str); - delegate single ended; -} + struct RSplitNEnds { inner: RSplitEnds } -impl<'a, P: Pattern<'a>> SplitN<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".splitn(3, ' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "had a little lamb"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} + #[unstable(feature = "split_inclusive_variants", issue = "none")] + fn max_items; -impl<'a, P: Pattern<'a>> RSplitN<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_as_str)] - /// let mut split = "Mary had a little lamb".rsplitn(3, ' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "Mary had a little"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + fn as_str; } derive_pattern_clone! { @@ -1540,49 +1747,6 @@ impl<'a> SplitAsciiWhitespace<'a> { } } -impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { - /// Returns remainder of the split string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_inclusive_as_str)] - /// let mut split = "Mary had a little lamb".split_inclusive(' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), "had a little lamb"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} - -impl<'a, P: Pattern<'a>> SplitLeftInclusive<'a, P> { - /// Returns remainder of the splitted string - /// - /// # Examples - /// - /// ``` - /// #![feature(str_split_inclusive_as_str)] - /// #![feature(split_inclusive_variants)] - /// let mut split = "Mary had a little lamb".split_left_inclusive(' '); - /// assert_eq!(split.as_str(), "Mary had a little lamb"); - /// split.next(); - /// assert_eq!(split.as_str(), " had a little lamb"); - /// split.by_ref().for_each(drop); - /// assert_eq!(split.as_str(), ""); - /// ``` - #[inline] - #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] - pub fn as_str(&self) -> &'a str { - self.0.as_str() - } -} - /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 0066a62b8e24f..f4f78e1cfff95 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -15,7 +15,7 @@ mod validations; use self::iter::{ SplitEndsInternal, SplitInclusiveInternal, SplitInitiatorInternal, SplitLeftInclusiveInternal, - SplitNInclusiveInternal, SplitNLeftInclusiveInternal, SplitTerminatorInternal, + SplitTerminatorInternal, }; use self::pattern::{DoubleEndedSearcher, Pattern, ReverseSearcher, Searcher}; @@ -83,8 +83,8 @@ pub use iter::{ pub use validations::{next_code_point, utf8_char_width}; use iter::MatchIndicesInternal; +use iter::MatchesInternal; use iter::SplitInternal; -use iter::{MatchesInternal, SplitNInternal}; #[inline(never)] #[cold] @@ -1472,7 +1472,10 @@ impl str { /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitInclusive<'a, P> { + pub fn rsplit_inclusive<'a, P>(&'a self, pat: P) -> RSplitInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { RSplitInclusive(self.split_inclusive(pat).0) } @@ -1566,10 +1569,10 @@ impl str { /// ``` #[unstable(feature = "split_inclusive_variants", issue = "none")] #[inline] - pub fn rsplit_left_inclusive<'a, P: Pattern<'a>>( - &'a self, - pat: P, - ) -> RSplitLeftInclusive<'a, P> { + pub fn rsplit_left_inclusive<'a, P>(&'a self, pat: P) -> RSplitLeftInclusive<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { RSplitLeftInclusive(self.split_left_inclusive(pat).0) } @@ -1921,7 +1924,7 @@ impl str { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - SplitN(SplitNInternal { iter: self.split(pat).0, count: n }) + self.split(pat).max_items(n) } /// An iterator over substrings of this string slice, separated by a @@ -1973,7 +1976,7 @@ impl str { where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - RSplitN(self.splitn(n, pat).0) + self.rsplit(pat).max_items(n) } /// An iterator over substrings of the given string slice, separated by a @@ -2034,7 +2037,7 @@ impl str { n: usize, pat: P, ) -> SplitNInclusive<'a, P> { - SplitNInclusive(SplitNInclusiveInternal { iter: self.split_inclusive(pat).0, count: n }) + self.split_inclusive(pat).max_items(n) } /// An iterator over substrings of this string slice, separated by a @@ -2094,7 +2097,7 @@ impl str { where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - RSplitNInclusive(self.splitn_inclusive(n, pat).0) + self.rsplit_inclusive(pat).max_items(n) } /// An iterator over substrings of the given string slice, separated by a @@ -2155,10 +2158,7 @@ impl str { n: usize, pat: P, ) -> SplitNLeftInclusive<'a, P> { - SplitNLeftInclusive(SplitNLeftInclusiveInternal { - iter: self.split_left_inclusive(pat).0, - count: n, - }) + self.split_left_inclusive(pat).max_items(n) } /// An iterator over substrings of this string slice, separated by a @@ -2218,7 +2218,7 @@ impl str { where P: Pattern<'a, Searcher: ReverseSearcher<'a>>, { - RSplitNLeftInclusive(self.splitn_left_inclusive(n, pat).0) + self.rsplit_left_inclusive(pat).max_items(n) } /// Splits the string on the first occurrence of the specified delimiter and